欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Linux進(jìn)程間通信——使用流套接字

 更新時(shí)間:2017年04月27日 15:48:36   作者:ljianhui  
本篇文章將會(huì)簡(jiǎn)單地講述如何使用socket進(jìn)行簡(jiǎn)單的網(wǎng)絡(luò)編程。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧

前面說(shuō)到的進(jìn)程間的通信,所通信的進(jìn)程都是在同一臺(tái)計(jì)算機(jī)上的,而使用socket進(jìn)行通信的進(jìn)程可以是同一臺(tái)計(jì)算機(jī)的進(jìn)程,也是可以是通過(guò)網(wǎng)絡(luò)連接起來(lái)的不同計(jì)算機(jī)上的進(jìn)程。通常我們使用socket進(jìn)行網(wǎng)絡(luò)編程,這里將會(huì)簡(jiǎn)單地講述如何使用socket進(jìn)行簡(jiǎn)單的網(wǎng)絡(luò)編程。

一、什么是socket

socket,即套接字是一種通信機(jī)制,憑借這種機(jī)制,客戶(hù)/服務(wù)器(即要進(jìn)行通信的進(jìn)程)系統(tǒng)的開(kāi)發(fā)工作既可以在本地單機(jī)上進(jìn)行,也可以跨網(wǎng)絡(luò)進(jìn)行。也就是說(shuō)它可以讓不在同一臺(tái)計(jì)算機(jī)但通過(guò)網(wǎng)絡(luò)連接計(jì)算機(jī)上的進(jìn)程進(jìn)行通信。也因?yàn)檫@樣,套接字明確地將客戶(hù)端和服務(wù)器區(qū)分開(kāi)來(lái)。

二、套接字的屬性

套接字的特性由3個(gè)屬性確定,它們分別是:域、類(lèi)型和協(xié)議。

1、套接字的域

它指定套接字通信中使用的網(wǎng)絡(luò)介質(zhì),最常見(jiàn)的套接字域是AF_INET,它指的是Internet網(wǎng)絡(luò)。當(dāng)客戶(hù)使用套接字進(jìn)行跨網(wǎng)絡(luò)的連接時(shí),它就需要用到服務(wù)器計(jì)算機(jī)的IP地址和端口來(lái)指定聯(lián)網(wǎng)機(jī)器上的某個(gè)特定服務(wù),所以在使用socket作為通信的終點(diǎn),服務(wù)器應(yīng)用程序必須在開(kāi)始通信之前綁定一個(gè)端口,服務(wù)器在指定的端口等待客戶(hù)的連接。另一個(gè)域AF_UNIX表示UNIX文件系統(tǒng),它就是文件輸入/輸出,而它的地址就是文件名。

2、套接字類(lèi)型

因特網(wǎng)提供了兩種通信機(jī)制:流(stream)和數(shù)據(jù)報(bào)(datagram),因而套接字的類(lèi)型也就分為流套接字和數(shù)據(jù)報(bào)套接字。這里主要講流套接字。

流套接字由類(lèi)型SOCK_STREAM指定,它們是在AF_INET域中通過(guò)TCP/IP連接實(shí)現(xiàn),同時(shí)也是AF_UNIX中常用的套接字類(lèi)型。流套接字提供的是一個(gè)有序、可靠、雙向字節(jié)流的連接,因此發(fā)送的數(shù)據(jù)可以確保不會(huì)丟失、重復(fù)或亂序到達(dá),而且它還有一定的出錯(cuò)后重新發(fā)送的機(jī)制。

與流套接字相對(duì)的是由類(lèi)型SOCK_DGRAM指定的數(shù)據(jù)報(bào)套接字,它不需要建立連接和維持一個(gè)連接,它們?cè)贏F_INET中通常是通過(guò)UDP/IP協(xié)議實(shí)現(xiàn)的。它對(duì)可以發(fā)送的數(shù)據(jù)的長(zhǎng)度有限制,數(shù)據(jù)報(bào)作為一個(gè)單獨(dú)的網(wǎng)絡(luò)消息被傳輸,它可能會(huì)丟失、復(fù)制或錯(cuò)亂到達(dá),UDP不是一個(gè)可靠的協(xié)議,但是它的速度比較高,因?yàn)樗⒁恍枰偸且⒑途S持一個(gè)連接。

3、套接字協(xié)議

只要底層的傳輸機(jī)制允許不止一個(gè)協(xié)議來(lái)提供要求的套接字類(lèi)型,我們就可以為套接字選擇一個(gè)特定的協(xié)議。通常只需要使用默認(rèn)值。

三、套接字地址

每個(gè)套接字都有其自己的地址格式,對(duì)于AF_UNIX域套接字來(lái)說(shuō),它的地址由結(jié)構(gòu)sockaddr_un來(lái)描述,該結(jié)構(gòu)定義在頭文件sys/un.h中,它的定義如下:

struct sockaddr_un{ 
  sa_family_t sun_family;//AF_UNIX,它是一個(gè)短整型 
  char    sum_path[];//路徑名 
}; 

對(duì)于AF_INET域套接字來(lái)說(shuō),它的地址結(jié)構(gòu)由sockaddr_in來(lái)描述,它至少包括以下幾個(gè)成員:

struct sockaddr_in{ 
  short int      sin_family;//AF_INET 
  unsigned short int  sin_port;//端口號(hào) 
  struct in_addr    sin_addr;//IP地址 
}; 

而in_addr被定義為:

struct in_addr{ 
  unsigned long int s_addr; 
}; 

四、基于流套接字的客戶(hù)/服務(wù)器的工作流程

使用socket進(jìn)行進(jìn)程通信的進(jìn)程采用的客戶(hù)/服務(wù)器系統(tǒng)是如何工作的呢?

1、服務(wù)器端

首先服務(wù)器應(yīng)用程序用系統(tǒng)調(diào)用socket來(lái)創(chuàng)建一個(gè)套接安,它是系統(tǒng)分配給該服務(wù)器進(jìn)程的類(lèi)似文件描述符的資源,它不能與其他的進(jìn)程共享。

接下來(lái),服務(wù)器進(jìn)程會(huì)給套接字起個(gè)名字,我們使用系統(tǒng)調(diào)用bind來(lái)給套接字命名。然后服務(wù)器進(jìn)程就開(kāi)始等待客戶(hù)連接到這個(gè)套接字。

然后,系統(tǒng)調(diào)用listen來(lái)創(chuàng)建一個(gè)隊(duì)列并將其用于存放來(lái)自客戶(hù)的進(jìn)入連接。

最后,服務(wù)器通過(guò)系統(tǒng)調(diào)用accept來(lái)接受客戶(hù)的連接。它會(huì)創(chuàng)建一個(gè)與原有的命名套接不同的新套接字,這個(gè)套接字只用于與這個(gè)特定客戶(hù)端進(jìn)行通信,而命名套接字(即原先的套接字)則被保留下來(lái)繼續(xù)處理來(lái)自其他客戶(hù)的連接。

2、客戶(hù)端

基于socket的客戶(hù)端比服務(wù)器端簡(jiǎn)單,同樣,客戶(hù)應(yīng)用程序首先調(diào)用socket來(lái)創(chuàng)建一個(gè)未命名的套接字,然后將服務(wù)器的命名套接字作為一個(gè)地址來(lái)調(diào)用connect與服務(wù)器建立連接。

一旦連接建立,我們就可以像使用底層的文件描述符那樣用套接字來(lái)實(shí)現(xiàn)雙向數(shù)據(jù)的通信。

五、流式socket的接口及作用

socket的接口函數(shù)聲明在頭文件sys/types.h和sys/socket.h中。

1、創(chuàng)建套接字——socket系統(tǒng)調(diào)用

該函數(shù)用來(lái)創(chuàng)建一個(gè)套接字,并返回一個(gè)描述符,該描述符可以用來(lái)訪(fǎng)問(wèn)該套接字,它的原型如下:

int socket(int domain, int type, int protocol); 

函數(shù)中的三個(gè)參數(shù)分別對(duì)應(yīng)前面所說(shuō)的三個(gè)套接字屬性。protocol參數(shù)設(shè)置為0表示使用默認(rèn)協(xié)議。

2、命名(綁定)套接字——bind系統(tǒng)調(diào)用

該函數(shù)把通過(guò)socket調(diào)用創(chuàng)建的套接字命名,從而讓它可以被其他進(jìn)程使用。對(duì)于AF_UNIX,調(diào)用該函數(shù)后套接字就會(huì)關(guān)聯(lián)到一個(gè)文件系統(tǒng)路徑名,對(duì)于AF_INET,則會(huì)關(guān)聯(lián)到一個(gè)IP端口號(hào)。函數(shù)原型如下:

int bind( int socket, const struct sockaddr *address, size_t address_len); 

成功時(shí)返回0,失敗時(shí)返回-1;

3、創(chuàng)建套接字隊(duì)列——listen系統(tǒng)調(diào)用

該函數(shù)用來(lái)創(chuàng)建一個(gè)隊(duì)列來(lái)保存未處理的請(qǐng)求。成功時(shí)返回0,失敗時(shí)返回-1,其原型如下:

int listen(int socket, int backlog); 

backlog用于指定隊(duì)列的長(zhǎng)度,等待處理的進(jìn)入連接的個(gè)數(shù)最多不能超過(guò)這個(gè)數(shù)字,否則往后的連接將被拒絕,導(dǎo)致客戶(hù)的連接請(qǐng)求失敗。調(diào)用后,程序一直這個(gè)IP端口,如果有連接請(qǐng)求,就把它加入到這個(gè)隊(duì)列中。

4、接受連接——accept系統(tǒng)調(diào)用

該系統(tǒng)調(diào)用用來(lái)等待客戶(hù)建立對(duì)該套接字的連接。accept系統(tǒng)調(diào)用只有當(dāng)客戶(hù)程序試圖連接到由socket參數(shù)指定的套接字上時(shí)才返回,也就是說(shuō),如果套接字隊(duì)列中沒(méi)有未處理的連接,accept將阻塞直到有客戶(hù)建立連接為止。accept函數(shù)將創(chuàng)建一個(gè)新套接字來(lái)與該客戶(hù)進(jìn)行通信,并且返回新套接字的描述符,新套接字的類(lèi)型和服務(wù)器套接字類(lèi)型是一樣的。它的原型如下:

int accept(int socket, struct sockaddr *address, size_t *address_len); 

address為連接客戶(hù)端的地址,參數(shù)address_len指定客戶(hù)結(jié)構(gòu)的長(zhǎng)度,如果客戶(hù)地址的長(zhǎng)度超過(guò)這個(gè)值,它將會(huì)截?cái)唷?/p>

5、請(qǐng)求連接——connect系統(tǒng)調(diào)用

該系統(tǒng)調(diào)用用來(lái)讓客戶(hù)程序通過(guò)在一個(gè)未命名套接字和服務(wù)器套接字之間建立連接的方法來(lái)連接到服務(wù)器。它的原型如下:

int connect(int socket, const struct sockaddr *address, size_t address_len); 

參數(shù)socket指定的套接字連接到參數(shù)addres指定的服務(wù)器套接字。成功時(shí)返回0,失敗時(shí)返回-1.

6、關(guān)閉socket——close系統(tǒng)調(diào)用

該系統(tǒng)調(diào)用用來(lái)終止服務(wù)器和客戶(hù)上的套接字連接,我們應(yīng)該總是在連接的兩端(服務(wù)器和客戶(hù))關(guān)閉套接字。

六、進(jìn)程使用流式socket進(jìn)行通信

下面用多個(gè)客戶(hù)程序和一個(gè)服務(wù)器程序來(lái)展示進(jìn)程間如何利用套接字進(jìn)行通信。

sockserver.c是一個(gè)服務(wù)器程序,它首先創(chuàng)建套接字,然后綁定一個(gè)端口再套接字,忽略子進(jìn)程的停止消息等,然后它進(jìn)入循環(huán),一直循環(huán)檢查是否有客戶(hù)連接到服務(wù)器,如果有,則調(diào)用fork創(chuàng)建一個(gè)子進(jìn)程來(lái)處理請(qǐng)求。利用read系統(tǒng)調(diào)用來(lái)讀取客戶(hù)端發(fā)來(lái)的信息,利用write系統(tǒng)調(diào)用來(lái)向客戶(hù)端發(fā)送信息。這個(gè)服務(wù)器的工作非常簡(jiǎn)單,就是把客戶(hù)發(fā)過(guò)來(lái)的字符+1,再發(fā)送回給客戶(hù)。

sockclient.c是一個(gè)客戶(hù)程序,它同樣要先創(chuàng)建套接,然后連接到指定IP端口服務(wù)器,如果連接成功,就用write來(lái)發(fā)送信息給服務(wù)器,再用read獲取服務(wù)器處理后的信息,再輸出。

服務(wù)器sockserver.c的源代碼如下:

#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <signal.h> 
#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
  int server_sockfd = -1; 
  int client_sockfd = -1; 
  int client_len = 0; 
  struct sockaddr_in server_addr; 
  struct sockaddr_in client_addr; 
  //創(chuàng)建流套接字 
  server_sockfd = socket(AF_INET, SOCK_STREAM, 0); 
  //設(shè)置服務(wù)器接收的連接地址和端口 
  server_addr.sin_family = AF_INET;//指定網(wǎng)絡(luò)套接字 
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//接受所有IP地址的連接 
  server_addr.sin_port = htons(9736);//綁定到9736端口 
  //綁定(命名)套接字 
  bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); 
  //創(chuàng)建套接字隊(duì)列,套接字 
  listen(server_sockfd, 5); 
  //忽略子進(jìn)程停止或退出信號(hào) 
  signal(SIGCHLD, SIG_IGN); 

  while(1) 
  { 
    char ch = '\0'; 
    client_len = sizeof(client_addr); 
    printf("Server waiting\n"); 
    //接受連接,創(chuàng)建新的套接字 
    client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_len); 

    if(fork() == 0) 
    { 
      //子進(jìn)程中,讀取客戶(hù)端發(fā)過(guò)來(lái)的信息,處理信息,再發(fā)送給客戶(hù)端 
      read(client_sockfd, &ch, 1); 
      sleep(5); 
      ch++; 
      write(client_sockfd, &ch, 1); 
      close(client_sockfd); 
      exit(0); 
    } 
    else 
    { 
      //父進(jìn)程中,關(guān)閉套接字 
      close(client_sockfd); 
    } 
  } 
} 

客戶(hù)sockclient.c的源代碼如下:

#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
  int sockfd = -1; 
  int len = 0; 
  struct sockaddr_in address; 
  int result; 
  char ch = 'A'; 
  //創(chuàng)建流套接字 
  sockfd = socket(AF_INET, SOCK_STREAM, 0); 
  //設(shè)置要連接的服務(wù)器的信息 
  address.sin_family = AF_INET;//使用網(wǎng)絡(luò)套接字 
  address.sin_addr.s_addr = inet_addr("127.0.0.1");//服務(wù)器地址 
  address.sin_port = htons(9736);//服務(wù)器端口 
  len = sizeof(address); 
  //連接到服務(wù)器 
  result = connect(sockfd, (struct sockaddr*)&address, len); 

  if(result == -1) 
  { 
    perror("ops:client\n"); 
    exit(1); 
  } 
  //發(fā)送請(qǐng)求給服務(wù)器 
  write(sockfd, &ch, 1); 
  //從服務(wù)器獲取數(shù)據(jù) 
  read(sockfd, &ch, 1); 
  printf("char form server = %c\n", ch); 
  close(sockfd); 
  exit(0); 
} 

運(yùn)行結(jié)果如下:

在本例子中,我們啟動(dòng)了一個(gè)服務(wù)器程序和三個(gè)客戶(hù)程序,從運(yùn)行的結(jié)果來(lái)看,客戶(hù)端發(fā)送給服務(wù)器程序的所有請(qǐng)求都得到了處理,即把A變成了B。對(duì)于服務(wù)器和客戶(hù)程序之間使用的read和write系統(tǒng)調(diào)用跟使用命名管道時(shí)阻塞的read、write系統(tǒng)調(diào)用一樣。例如客戶(hù)程序調(diào)用read時(shí),如果服務(wù)器程序沒(méi)有向指定的客戶(hù)程序的socket中寫(xiě)入信息,則read調(diào)用會(huì)一直阻塞。

七、流式套接字給我印象

給我的感覺(jué)是流式套接字很像命名管道,但是它卻可以使不在同一臺(tái)計(jì)算機(jī)而通過(guò)網(wǎng)絡(luò)連接的不同計(jì)算機(jī)上的進(jìn)程進(jìn)行通信,功能真是非常的強(qiáng)大。

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • shell 使用數(shù)組作為函數(shù)參數(shù)的方法(詳解)

    shell 使用數(shù)組作為函數(shù)參數(shù)的方法(詳解)

    下面小編就為大家?guī)?lái)一篇shell 使用數(shù)組作為函數(shù)參數(shù)的方法(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-04-04
  • crontab實(shí)現(xiàn)每隔多少天執(zhí)行一次腳本的兩種方法

    crontab實(shí)現(xiàn)每隔多少天執(zhí)行一次腳本的兩種方法

    相信大家在工作中,經(jīng)常會(huì)遇到定時(shí)執(zhí)行腳本的功能要求,或某個(gè)命令的情況。那么下面這篇文章主要給大家介紹了關(guān)于crontab實(shí)現(xiàn)每隔多少天執(zhí)行一次腳本的相關(guān)資料,對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-08-08
  • linux下命令行操作快捷鍵及技巧(分享)

    linux下命令行操作快捷鍵及技巧(分享)

    下面小編就為大家?guī)?lái)一篇linux下命令行操作快捷鍵及技巧(分享)。小編覺(jué)的挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • Linux中使用mtime查看文件的最后修改時(shí)間的操作方法

    Linux中使用mtime查看文件的最后修改時(shí)間的操作方法

    在?Linux?系統(tǒng)中,mtime?是文件的一個(gè)重要屬性,它記錄了文件的最后修改時(shí)間,了解文件的最后修改時(shí)間對(duì)于系統(tǒng)管理和數(shù)據(jù)追蹤非常重要,在本文中,我們將深入探討如何使用?mtime?查看文件的最后修改時(shí)間,需要的朋友可以參考下
    2024-05-05
  • 通過(guò)shell腳本循環(huán)進(jìn)入目錄執(zhí)行命令的方法

    通過(guò)shell腳本循環(huán)進(jìn)入目錄執(zhí)行命令的方法

    今天小編就為大家分享一篇通過(guò)shell腳本循環(huán)進(jìn)入目錄執(zhí)行命令的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • Shell腳本入門(mén)之編寫(xiě)格式與執(zhí)行方式的實(shí)現(xiàn)

    Shell腳本入門(mén)之編寫(xiě)格式與執(zhí)行方式的實(shí)現(xiàn)

    這篇文章主要介紹了Shell腳本入門(mén)之編寫(xiě)格式與執(zhí)行方式的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Git代碼提交流程及git命令匯總(基礎(chǔ)篇)

    Git代碼提交流程及git命令匯總(基礎(chǔ)篇)

    git 現(xiàn)在的火爆程度非同一般,它被廣泛地用在大型開(kāi)源項(xiàng)目,團(tuán)隊(duì)開(kāi)發(fā),以及獨(dú)立開(kāi)發(fā)者,甚至學(xué)生之中。這篇文章給大家介紹一些Git代碼提交流程和Git基礎(chǔ)命令的使用,需要的朋友參考下吧
    2017-12-12
  • Linux paste命令用法匯總

    Linux paste命令用法匯總

    paste命令是linux下的一個(gè)文件管理命令,paste命令可以把每個(gè)文件以列對(duì)列的方式,然后一列列地加以合并,也就是合并兩個(gè)文件,這篇文章主要介紹了Linux paste命令使用方法,感興趣的朋友一起看看吧
    2022-12-12
  • Linux Shell 數(shù)組的創(chuàng)建及使用技巧

    Linux Shell 數(shù)組的創(chuàng)建及使用技巧

    這篇文章主要介紹了Linux Shell 數(shù)組的創(chuàng)建及使用技巧,本文講解了數(shù)組定義、數(shù)組讀取與賦值以及特殊使用,需要的朋友可以參考下
    2015-07-07
  • Linux?du命令實(shí)現(xiàn)根據(jù)文件或者文件夾大小排序輸出

    Linux?du命令實(shí)現(xiàn)根據(jù)文件或者文件夾大小排序輸出

    Linux是一個(gè)強(qiáng)大的操作系統(tǒng),廣泛用于服務(wù)器和個(gè)人計(jì)算機(jī),本文主要來(lái)和大家聊聊如何利用du命令實(shí)現(xiàn)根據(jù)文件或者文件夾大小排序輸出,感興趣的可以了解下
    2023-09-09

最新評(píng)論