不同計算機(通過網絡相連)上運行的進程相互通信機制稱為網絡進程間通信(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
幾個定義:
- IP地址:即依照TCP/IP協議分配給本地主機的網絡地址,兩個進程要通訊,任一進程首先要知道通訊對方的位置,即對方的IP。
- 端口號:用來辨別本地通訊進程,一個本地的進程在通訊時均會占用一個端口號,不同的進程端口號不同,因此在通訊前必須要分配一個沒有被訪問的端口號。
- 連接:指兩個進程間的通訊鏈路。
- 半相關:網絡中用一個三元組可以在全局唯一標志一個進程:(協議,本地地址,本地端口號)這樣一個三元組,叫做一個半相關,它指定連接的每半部分。
- 全相關:一個完整的網間進程通信需要由兩個進程組成,並且只能使用同一種高層協議。也就是說,不可能通信的一端用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 5struct
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