深入淺出TCP之listen

原文:http://blog.chinaunix.net/uid-29075379-id-3858844.html

int listen(int fd, int backlog);


有幾個概念需要在開頭澄清一下

TCP socket分兩種,監聽socket和傳輸socket兩種

監聽socket:負責處理網絡上來的連接請求(客戶端的syn包到達便是連接請求來了,如果不知道syn包,請參看一下TCP三次握手);

傳輸socket:負責在網絡上的兩個端點之間傳輸TCP數據。


未決socket:pending socket,就是某客戶端的syn包到達,內核爲這個syn包對應的tcp請求生成一個socket,但是此時三次握手並沒有完成,這樣的socket就是pending socket,是未決連接,沒有經過三次握手認證的tcp連接。

已建立連接的socket:established socket,tcp服務器利用三次握手完成對客戶端的簡單認證之後,未決socket就變成已連接socket,後續可以用這個socket傳輸數據。

內核爲每個tcp服務器維護兩個socket隊列:未決socket隊列和已建立連接的socket隊列

29075379_1377067462LOlL.jpg

圖 1


現在進入主題:)

在TCP服務器端創建socket完畢,調用listen函數的時候,系統下層發生了以下動作:

1. 將剛纔創建的(fd所標示的)socket轉換爲此tcp服務器的監聽socket,讓此socket進入監聽請求模式,此socket的tcp狀態由CLOSE轉至LISTEN.

2.內核爲此監聽socket所對應的tcp服務器建立一個未決socket隊列和一個已建立連接socket隊列

backlog這個參數用來決定未決socket隊列的長度,有個映射關係,0表示長度可以無限大。


現在來串一串整個過程

監聽socket收到某客戶端的syn包,第一次握手完成;

然後內核爲此syn請求生成一個pending socket,例如圖1中的socket5,標記狀態爲SYN_RECV,並且將socket5加入相應的pending socket隊列,並且服務器發出ack和syn,第二次握手完成。

後續針對此socket5有兩種可能

1可能

過會兒客戶端響應了服務器的syn(第三個ack到達),第三次握手結束。內核觸發accept函數執行,將socket5狀態標記爲ESTABLISHED,並且將此socket5由pending socket queue移至establishedsocket queue,如圖2

29075379_1377067494nRf1.jpg

圖2


2可能

客戶端的最後一個ack並未來到,過很久,圖1中的socket5超時了,被移除,如圖3

29075379_1377067514BX3v.jpg

圖3


到這兒,listen的作用應該清楚了


另外針對此listen,有兩個極限情況導致的拒絕服務情況需要考慮

backlog設置過小,pending socket隊列已滿,此時客戶端調用connect發送syn分節給服務器端請求連接,服務端會忽略此syn包,客戶端收不到syn的ack,會觸發syn超時,這個超時時間比較長,重發syn,導致客戶端長時間連接不上。

backlog設置爲0或者過大,只要收到syn包,就會在pending socket隊列中增加節點,這個容易導致物理內存耗盡

Syn flood就是***pending socket隊列的


linux內核可以全局設置此pending socket隊列大小

/proc/sys/net/ipv4/tcp_max_syn_backlog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章