1. 程式人生 > >linux網路程式設計之TCP介面詳解

linux網路程式設計之TCP介面詳解

socket

int socket(int domain, int type, intprotocol);

    監聽套接字描述符由socket建立,隨後用作bind和listen的第一個引數。一個伺服器通常僅建立一個監聽套接字,他在該伺服器的生命週期內一直存在。


connect

int connect(intsockfd, const struct sockaddr *addr,socklen_t addrlen);

如果是TCP套接字,呼叫connect將激發TCP的三路握手,僅在連線建立成功或出錯時才返回。

         1.若TCP客戶沒有收到SYN分節響應,返回ETIMEOUT錯誤,例如呼叫connect後,核心傳送SYN後無響應重傳多次後仍未有響應則返回本錯誤。

         2.若對客戶的SYN響應是RST,則表明該伺服器主機在我們指定的埠沒有程序在等待與之連線(伺服器程序也許沒有在執行)。客戶一接收到

         RST馬上返回ECONNREFUSED。

         3.RST是TCP在發生錯誤時傳送的一種TCP分節。產生RST的單個條件是

         3.1 目的地為某埠的SYN到達,而該埠上沒有正在監聽的伺服器;

         3.2 TCP想取消一個已有的連線;

         3.3 TCP接收到一個根本不存在的連線上的分節。

         4.按照TCP狀態轉換圖,connect導致當前套接字從CLOSED狀態轉移到SYN_SENT狀態,若成功則轉移至ESTABLISHED狀態。若connect失敗則該套接字不再可用,必須關閉套接字,重新呼叫socket。

bind

int bind(intsockfd, const struct sockaddr *addr,socklen_t addrlen);

         1.伺服器在啟動時捆綁他們的眾所周知的埠,如果一個TCP客戶/服務未曾呼叫bind捆綁一個埠,當呼叫connect/listen時,核心就要為相應套接字選擇一個臨時埠。讓核心來選臨時埠對於TCP客戶來說時正常的,除非應用需要一個預留埠,然而對於TCP伺服器來說罕見,因為伺服器是通過眾所周知埠被大家認識的。

    2.程序可以把一個特定的IP地址繫結到套接字上,這個IP地址必須屬於其所在主機的網路介面之一。對於TCP客戶即為套接字上傳送的IP資料報指派了源IP地址。對於TCP伺服器,限定該套接字只接收目的為該IP地址的客戶連線。TCP客戶通常不把IP地址捆綁到套接字,當連線時核心根據所用外出網路介面來選擇源IP地址,外出介面取決於到達伺服器所需的路徑。TCP伺服器若沒有把IP地址繫結到套接字上,核心就把客戶傳送的SYN的目的IP地址作為源IP地址。例如指定IP地址為通配地址,那麼核心將等到套接字已連線(TCP)或已在套接字上發出資料報(UDP)時才選擇一個本地IP地址。

         3.執行繫結通配地址伺服器,當一個連線到達時,伺服器呼叫getsockname獲取來自客戶的目的IP地址,然後根據這個客戶連線所發往的IP地址來處理客戶的請求。

    4.捆綁非通配IP地址的好處是把一個給定目的IP地址解複用到一個給定的伺服器程序是由核心而不是伺服器程序本身完成。

listen

int listen(intsockfd, int backlog);

         1.當socket建立一個套接字時,他被假設為一個主動套接字,即一個將呼叫connect發起連線的客戶套接字,listen把一個未連線套接字轉換為一個被動套接字,指示核心應接收套接字的連線請求。套接字從CLOSED狀態轉換為LISTEN狀態。

         2.本函式第二個引數規定了核心為套接字排隊的最大連線個數。核心為任何一個給定的監聽套接字維護兩個佇列:


         2.1 未完成連線佇列

         已由某個客戶端發出併到達伺服器的的SYN分節對應其中一項,伺服器正在等待完成相應的TCP三路握手過程。這些套接字處於SYN_RCVD狀態。

         2.2 已完成連線佇列

         每個已完成TCP三路握手過程的客戶對應其中一項,這些套接字處於ESTABLISHED狀態。

         每當在未完成連線佇列中建立一項時,來自監聽套接字的引數就複製到即將建立的連線中。連線的建立機制時完全自動的,無需服務起程序插手。

    當來自客戶的SYN到達,TCP在未完成佇列中建立一個新項,然後響應以三路握手的第二個分節即伺服器的SYN響應,其中捎帶對客戶SYN的ACK。這一項一直保留在未完成連線佇列中,直到三路握手的第三個分節(客戶對伺服器SYN的ACK)到達或者該項超時(75s)為止。三路握手正常完成,該項就從未完成連線佇列移至已完成連線佇列的對尾。


         3.對於繁忙的web伺服器,對著客戶SYN分節的到達,未完成連線佇列中的項數可能增大,等著三路握手完成,所以backlog值應該設定大一些,預設最大值見/proc/sys/net/core/somaxconn。

         4.當一個客戶SYN到達時,若這些佇列時滿的,TCP就忽略該分節(不傳送RST),因為這種情況時暫時的,客戶TCP將重發SYN,期望不久就能在這些佇列中找到可用空間,若伺服器TCP立即響應一個RST,客戶的connect呼叫就會立即返回一個錯誤,強制應用程序處理這種情況,而不是讓TCP的正常重傳機制來處理。客戶無法區分響應SYN的RST是因為“服務程序在監聽”還是“該埠有伺服器在監聽但是他的佇列滿了”。

         5.在三路握手完成之後,但是在伺服器呼叫accept之前到達的資料應由伺服器TCP排隊,最大資料量為相應已連線套接字的接收緩衝區大小。

accept

int accept(intsockfd, struct sockaddr *addr, socklen_t *addrlen);

用於從已完成連線佇列隊頭返回下一個已完成連線,若已完成連線佇列為空,程序被投入睡眠。

    accept成功,其返回值是由核心自動生成的一個全新描述符稱為已連線套接字,代表與所返回客戶的TCP連線。也就是說對於伺服器程序與客戶之間的TCP三路握手過程已經完成。當伺服器完成對某個給定客戶的服務時,相應的已連線套接字就被關閉。