參數family指明協議族(family),該參數也每每被稱爲協議域(domain)。因此有的書上聲明以下:html
並且對於socket函數第一個參數,在不一樣書籍上可能會看到不一樣前綴的取值常量列表,以下兩圖所示:服務器
AF_xxx與PF_xxx:網絡
AF_前綴表地址族,PF_前綴表示協議族。歷史上曾有這樣的想法:單個協議族能夠支持多個地址族,PF_值用來建立套接口,而AF_值用於套接口地址結構。但實際上,支持多個地址族的協議族歷來就未實現過,並且頭文件<sys/socket.h>中爲一給定協議定義的PF_值老是與此協議的AF_值相等。併發
客戶在調用函數connect前沒必要非得調用bind函數,由於若是須要的話,內核會肯定源IP地址,並選擇一個臨時端口做爲源端口。dom
若是是TCP套接口,調用connect函數將激發TCP的三路握手過程,並且僅在鏈接創建成功或出錯時才返回,其中出錯返回可能有如下幾種狀況:socket
(1)若TCP客戶沒有收到SYN分節的響應,則返回ETIMEDOUT錯誤。函數
(2)若對客戶的SYN的響應是RST(表示復位),則代表該服務器主機在咱們指定的端口上沒有進程在等待與之鏈接(例如服務器進程也許沒在運行)。這是一種硬錯誤(hard error),客戶一接收到RST就立刻返回ECONNREFUSED錯誤。spa
(3)若客戶發出的SYN在中間的某個路由器上引起了一個「destination unreachable」(目的地不可達)ICMP錯誤,則認爲是一種軟錯(soft error)。客戶主機內核保存該消息,並按必定時間間隔延遲重發SYN。若在某個規定的時間(4.4BSD規定爲75秒)後仍未收到響應,則 把保存的消息(即ICMP錯誤)做爲EHOSTUNREACH或ENETUNREACH錯誤返回給進程。3d
若connect失敗則該套接口再也不可用,必須關閉,咱們不能對這樣的套接口再次調用connect函數。當循環調用函數connect嘗試給定主機的各個IP地址直到有一個成功時,每次connect失敗後,都必須close當前的套接口描述字,從新調用socket。指針
進程能夠把一個特定的IP地址捆綁到它的套接口上,不過這個IP地址必須屬於其所在主機的網絡接口之一。對於TCP客戶,這就爲在該套接口上發送的IP數據報指派了源IP地址。對於TCP服務器,這就限定該套接口只接收那些目的地爲這個IP地址的客戶鏈接。
TCP客戶一般不把IP地址捆綁到它的套接口上。當鏈接套接口時,內核將根據所用外出網絡接口來選擇源IP地址,而所用外出接口則取決於到達服務器所需的路徑。
若是指定端口號爲0,那麼內核就在bind被調用時選擇一個臨時端口;
若是指定IP地址爲通配地址,那麼內核將等到套接口已鏈接(TCP)或已在套接口上發出數據報(UDP)時才選擇一個本地IP地址。
對於IPv4來講,通配地址由常值INADDR_ANY來指定,其值通常爲0. 它告知內核去選擇IP地址。
不管是網絡字節序仍是主機字節序,INADDR_ANY的值(爲0)都同樣,所以使用htonl並不是必須。不過既然頭文件<netinet/in.h>中定義的全部INADDR_常值都是按照主機字節序定義的,咱們應該對全部這些常值都使用htonl。
listen函數作兩件事情:
(1)當socket函數建立一個套接口時,它被假設爲一個主動套接口,也就是說,它是一個將調用connect發起鏈接的客戶套接口。listen函數把一個未鏈接的套接口轉換成一個被動套接口,指示內核應該接受指向該套接口的鏈接請求。調用listen致使套接口從CLOSED狀態轉換到LISTEN狀態。
(2)backlog參數規定了內核應該爲相應套接口排隊的最大鏈接個數。
爲了理解其中的backlog參數,咱們必須認識到內核爲任何一個給定的監聽套接口維護兩個隊列:
(1)未完成鏈接隊列(incomplete connection queue),每一個這樣的SYN分節對應其中一項:已由客戶發出併到達服務器,而服務器正在等待完成相應的TCP三路握手過程。這些套接口處於SYN_RCVD狀態。
(2)已完成鏈接隊列(completed connection queue),每一個已完成TCP三路握手過程的客戶對應其中一項。這些套接口處於ESTABLISHED狀態。
當進程調用accept時,已完成鏈接隊列中的隊頭項將返回給進程,或者若是該隊列爲空,那麼進程將被投入睡眠,直到TCP在該隊列中放入一項才喚醒它。
不要把backlog定義爲0,由於不一樣的實現對此有不一樣的解釋。若是不想讓客戶鏈接到你的監聽套接口上,那就關掉該監聽套接口。
accept函數由TCP服務器調用,用於從已完成鏈接隊列隊頭返回下一個已完成鏈接。若是已完成鏈接隊列爲空,那麼進程被投入睡眠(假定套接口爲缺省的阻塞方式)。
參數cliaddr和addrlen用來返回已鏈接的對端進程(客戶)的協議地址。
若是accept成功,那麼其返回值是由內核自動生成的一個全新描述字,表明與所返回客戶的TCP鏈接。
在討論accept函數時,咱們稱它的第一個參數爲監聽套接口(listening socket)描述字(由socket建立,隨後用做bind和listen的第一個參數的描述字),稱它的返回值爲已鏈接套接口(connected socket)描述字。區分這兩個套接口很是重要。一個服務器一般僅僅建立一個監聽套接口,它在服務器的生命期內一直存在。內核爲每一個由服務器進程接受的客戶鏈接建立一個已鏈接套接口(也就是說對於它的TCP三路握手過程已經完成)。當服務器完成對於某個給定客戶的服務時,相應的已鏈接套接口就被關閉。
本函數最多返回三個值:一個既多是新套接口描述字也多是出錯指示的整數、客戶進程的協議地址(由cliaddr指針所指)以及該地址的大小(由addrlen指針所指)。若是咱們對返回客戶協議地址不感興趣,那麼能夠把cliaddr和addrlen均設置爲空指針。
fork函數:http://www.cnblogs.com/nufangrensheng/p/3509492.html。
exec函數:http://www.cnblogs.com/nufangrensheng/p/3510821.html。
UNIX一般的close函數也用來關閉套接口,並終止TCP鏈接。
close一個TCP套接口的缺省行爲是把該套接口標記成已關閉,而後當即返回到調用進程。該套接口描述字不能再由調用進程使用,也就是說它不能再做爲read或write的第一個參數。然而TCP將嘗試發送已排隊等待發送到對端的任何數據,發送完畢後發生的是正常的TCP鏈接終止序列。
getsockname:返回與某個套接口關聯的本地協議地址。
getpeername:返回與某個套接口關聯的遠地協議地址。
這兩個函數返回與某個網絡鏈接的兩端中任何一端相關聯的協議地址,對於IPv4和IPv6來講,就是IP地址和端口號的組合。
須要這兩個函數的理由以下:
(1)在沒有調用bind的TCP客戶上,connect成功返回後,getsockname用於返回由內核賦予該鏈接的本地IP地址和本地端口號。
(2)在以端口號0調用bind(告知內核去選擇本地端口號)後,getsockname用於返回由內核賦予的本地端口號。
(3)getsockname可用於獲取某個套接口的地址族。
(4)在一個以通配IP地址調用bind以後的TCP服務器上,與某個客戶的鏈接一旦創建(accept成功返回),getsockname就能夠用於返回由內核賦予該鏈接的本地IP地址。在這樣的調用中,套接口描述字必須是已鏈接套接口的描述字,而不是監聽套接口的描述字。
(5)當一個服務器是由調用過accept的某個進程經過調用exec更換了程序時,它可以獲取客戶身份的惟一途徑即是調用getpeername。
全部客戶和服務器都從調用socket開始,它返回一個套接口描述字。客戶隨後調用connect,服務器則調用bind、listen和accept。套接口一般使用標準的close函數關閉。