歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

網絡IPC:套接字

網絡進程間通信:socket API簡介

不同計算機(通過網絡相連)上運行的進程相互通信機制稱為網絡進程間通信(network IPC)。

在本地可以通過進程PID來唯一標識一個進程,但是在網絡中這是行不通的。其實TCP/IP協議族已經幫我們解決了這個問題,網絡層的“ip地址”可以唯一標識網絡中的主機,而傳輸層的“協議+端口”可以唯一標識主機中的應用程序(進程)。這樣利用三元組(ip地址,協議,端口)構成套接字,就可以標識網絡的進程了,網絡中的進程通信就可以利用這個標志與其它進程進行交互。

套接字是通信端口的抽象!通過套接字網絡IPC接口,進程能夠使用該接口和其他進程通信。

部分參考:UNIX環境高級編程中文第二版PDF高清版 下載地址  http://www.linuxidc.net/thread-2063-1-1.html

Unix環境高級編程 源代碼地址 http://www.linuxidc.com/Linux/2011-04/34826.htm

Unix環境高級編程源碼編譯 http://www.linuxidc.com/Linux/2011-09/42503.htm

apue.h頭文件(Unix環境高級編程) http://www.linuxidc.com/Linux/2012-01/51729.htm

《Unix環境高級編程》(第二版)apue.h的錯誤 http://www.linuxidc.com/Linux/2011-04/34662.htm

Unix環境高級編程第二版讀書筆記 http://www.linuxidc.com/Linux/2011-04/34235.htm

《Unix環境高級編程》中apue.h的問題 http://www.linuxidc.com/Linux/2013-01/77686.htm

幾個定義:

  1. IP地址:即依照TCP/IP協議分配給本地主機的網絡地址,兩個進程要通訊,任一進程首先要知道通訊對方的位置,即對方的IP。
  2. 端口號:用來辨別本地通訊進程,一個本地的進程在通訊時均會占用一個端口號,不同的進程端口號不同,因此在通訊前必須要分配一個沒有被訪問的端口號。
  3. 連接:指兩個進程間的通訊鏈路。
  4. 半相關:網絡中用一個三元組可以在全局唯一標志一個進程:(協議,本地地址,本地端口號)這樣一個三元組,叫做一個半相關,它指定連接的每半部分。
  5. 全相關:一個完整的網間進程通信需要由兩個進程組成,並且只能使用同一種高層協議。也就是說,不可能通信的一端用TCP協議,而另一端用UDP協議。因此一個完整的網間通信需要一個五元組來標識:(協議,本地地址,本地端口號,遠地地址,遠地端口號),這樣一個五元組,叫做一個相關(association),即兩個協議相同的半相關才能組合成一個合適的相關,或完全指定組成一連接。

套接字描述符

套接字是端點的抽象。與應用進程要使用文件描述符訪問文件一樣,訪問套接字也需要用套接字描述符。套接字描述符在UNIX系統中是用文件描述符實現的。

要創建一個套接字,可以調用socket函數。

1 2 #include<sys/socket.h> int socket(int domain, int type, int protocol);

  參數:

作用:socket()用於創建一個socket描述符(socket descriptor),它唯一標識一個socket。

網絡字節序

網絡協議指定了字節序,因此異構計算機系統能夠交換協議信息而不會混淆字節序。TCP/IP協議棧采用大端字節序。應用進程交換格式化數據時,字節序問題就會出現。對於TCP/IP,地址用網絡字節序來表示,所以應用進程有時需要在處理器的字節序與網絡字節序之間轉換。

1 2 3 4 5 #include<arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);

這些函數名很好記,h表示host,n表示network, l表示32位長整數,s表示16位短整數

在將一個地址綁定到socket的時候,請先將主機字節序轉換成為網絡字節序,對主機字節序不要做任何假定,務必將其轉化為網絡字節序再賦給socket!

將套接字與地址綁定

與客戶端的套接字關聯的地址意義不大,可以讓系統選擇一個默認的地址。然而,對於服務器,需要給一個接收客戶端請求的套接字綁定一個眾所周知的地址。客戶端應有一種方法用以連接服務器的地址,最簡單的方法就是為服務器保留一個地址並且在/etc/services或某個名字服務(name service)中注冊。

  可以用bind函數來搞定這個問題:

1 2 3 #include <sys/types.h>        #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

參數:

第一個參數:bind()函數把一個地址族中的特定地址賦給該sockfd(套接字描述字)。例如對應AF_INET、AF_INET6就是把一個ipv4或ipv6地址和端口號組合賦給socket。 

第二個參數:struct sockaddr *指針,指向要綁定給sockfd的協議地址。這個地址結構根據地址創建socket時的地址協議族的不同而不同:

地址格式

地址標識了特定通信域中的套接字端點,地址格式與特定的通信域相關。為使不同格式地址能夠被傳入到套接字函數,地址需被強轉為通用的地址結構sockaddr表示。

1 2 //頭文件 #include<netinet/in.h>

struct sockaddr 是一個通用地址結構,該結構定義如下: 

1 2 3 4 5 struct sockaddr {    sa_family_t sa_family;    char        sa_data[14]; }

IPV4因特網域:

1 2 3 4 5 6 7 8 9 10 11 12 //ipv4對應的是: /* 網絡地址 */ struct in_addr {     uint32_t      s_addr;    /* address in network byte order */ };   struct sockaddr_in {     sa_family_t    sin_family;    /* address family: AF_INET */     in_port_t      sin_port;      /* port in network byte order */     struct in_addr sin_addr;      /* internet address */ };

IPv6因特網域:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 //ipv6對應的是: struct in6_addr {     unsigned char  s6_addr[16];  /* IPv6 address */ };   struct sockaddr_in6 {     sa_family_t    sin6_family;  /* AF_INET6 */     in_port_t      sin6_port;    /* port number */     uint32_t        sin6_flowinfo; /* IPv6 flow information */     struct in6_addr sin6_addr;    /* IPv6 address */     uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ };

  Unix域對應的是: 

1 2 3 4 5 6 7 #define UNIX_PATH_MAX    108   struct sockaddr_un {     sa_family_t sun_family;              /* AF_UNIX */     char        sun_path[UNIX_PATH_MAX];  /* pathname */ };

第三個參數:addrlen 對應的是地址的長度

返回值:成功返回0,出錯返回-1

作用:將套接字與端口號綁定,即把一個ip地址和端口號組合賦給socket

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2016-08/134307p2.htm

Copyright © Linux教程網 All Rights Reserved