我們首先來說一下pf_inet和af_inet,雖然标準提倡在指定demain參數的時候,優先使用pf_inet,但是大量已經編寫的c代碼遵循舊的協定。目前情況是af_unix=pf_unix,af_inet=pf_inet。但是将來是不是這樣不好說啊。
不同于socketpari函數的demain參數隻能指定為pf_local,socket函數可以用于生成所支援的任何協定族的套接口,文法如下:
程式設計者通常為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