我們首先來說一下PF_INET和AF_INET,雖然標准提倡在指定demain參數的時候,優先使用PF_INET,但是大量已經編寫的c代碼遵循舊的協議。目前情況是AF_UNIX=PF_UNIX,AF_INET=PF_INET。但是將來是不是這樣不好說啊。
不同於socketpari函數的demain參數只能指定為PF_LOCAL,socket函數可以用於生成所支持的任何協議族的套接口,語法如下:
#include <sys/types.h> #include <sys/socket.h> int socket(int demain, int type , int protocol);
編程者通常為type參數取值如下:
SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW.
當編程者想在遠程套接口上實現I/O的時候,就可以使用SOCK_STREAM套接口選項。字節流中沒有分界線,也沒有邊界,沒有記錄的長度或者塊的大小,在接受端也不存在分組的概念,在接受端獲得的所有的數據都返回到調用者的緩沖區中。
上面可能說的不清楚,我們在詳細的解釋一下:加入本地主機想通過兩次獨立write調用遠程主機發送數據,過程如下:
1.本地進程寫入25字節,然后發送到遠程進程。
2.本地進程在寫入30個字節,然后發送到遠程進程。
3.遠程進程從套接口接收數據,接受緩沖區最大為256字節,接受進程共收到2次發送的55個字節。
也就是說本地進程執行了倆次獨立的操作,可能寫入了2個不同的消息或者數據結構,但是遠程進程並不關心本地進程進行了幾次寫操作。她只是將這55個字節作為一個整體來看待。
從上可以看出,一個流套接口不會保留任何的消息邊界,她只是簡單地向接收進程返回他所擁有的數據。
流套接口的另外一個重要的性質是有序性。她可以保證把字節按照寫入的順序發送到接受端。SOCK_STREWAM套接口可以確保接收程序完全按照數據發送的順序進行接收。
下面總結一下SOCK_STREAM性質:
1. 不保留消息邊界。2.保證接收字節順序和發送的順序一致。3.保證寫入的數據在接受端被無錯的接收。如果有錯誤發生,在嘗試玩所有的錯誤恢復措施之后,如果還是無法消除錯誤,那么流套接口就會回報錯誤。4.數據是通過一對連接的套接口傳輸的,SOCK_STREAM意味着在通信之前必須建立一個連接。
下面我們來談談SOCK_DGRAM類型:
在不需要考慮數據絕對有序性和可靠性的時候,我們可以使用SOCK_DGRAM。下面是她的一些性質:
1.分組發送后可能無序到達接受端。2.分組可能丟失。丟失了也不會采取措施補救,接受端也不知道有丟失。3.數據報分組有大小尺寸的限制,如果超出限制,在某些路由器或者節點上無法傳送。4.分組在不建立連接的情況下被發送到遠程的,這個也就容許本地進程每次將消息發送給不同IP地址上同樣的端口。
需要注意的是並不是每個協議族都可以使用所有的套接口類型,例如PF_INET支持SOCK_STREAM,但是不支持SOCK_SEQPACKET類型。
選擇協議
事實上,我們很少設定protocol參數的值,而只是簡單的設置為0 ,這個時候,Linux內核就會根據其他參數的情況自動選擇一個正確的協議。但是一些編程者習慣於明確的描述protocol參數的值,這個對於需要特定協議支持的程序來說很重要。
使用PF_LOCAL和SOCK_STREAM
在函數socket和socketpair中,對於PF_LOCAL套接口,我們可以對protocol參數使用0值,這個是protocol參數唯一支持的值。因為到目前為止,如果函數socket和socketpair函數的domain參數為PF_LOCAL/PF_UNIX的時候,protocol的參數的唯一有效值為0.
使用PF_LOCAL和SOCK_DGRAM
當需要保留消息邊界的時候,我們可以在本地套接口上使用SOCK_DGRAM,在domain參數為PF_LOCAL的SOCK_DGRAM套接口中,protocol參數的唯一有效值為0、
PS:套接口生成以后,他還處於“無名”狀態,就是說還沒有地址,編程者必須建立一個有效的地址,並通過bind函數把地址綁定到套接口。
使用PF_INET和SOCK_STREAM
目前,在domain參數為PF_INET的SOCK_STREAN的套接口中,protocol的參數為0意味着內核選擇IPPROTO_TCP,也就是套接口使用TCP/IP協議。
使用PF_INET和SOCK_DGRAM
這個組合告訴內核選擇UDP協議。也就是選擇IPPROTO_UDP。
下表是一個總結:
當然Linux支持許多的協議,此處不多說。
有關協議族的一些宏定義在sys/socket.h頭文件中,而實際上這個文件包含了另外一個定義協議宏常量的頭文件,它的路徑名是:
/usr/include/bits/sockett.h
我們可以使用grep命令將內核中可能支持的協議打印出:grep PF_ /usr/include/bits/socket.h