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隊列

圖 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移至established
socket queue,如圖2
圖2
2可能
用戶端的最後一個ack并未來到,過很久,圖1中的socket5逾時了,被移除,如圖3
圖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
還可以啟用tcp_syncookies,來緩解pending socket隊列的壓力
echo "1" > / proc/sys/net/ipv4/tcp_syncookies
但是,這兩個調整,對于巨量的synflood攻擊來說,都是治标不治本。