網路程式設計之每天學習一點點[day6]-----tcp三次握手和backlog
先看一副圖:
在linux2.2之前:
linux核心在底層維護一個由backlog指定大小的佇列。
客戶端傳送SYN(第一次握手),服務端收到SYN後,返回一個SYN/ACK(第二次握手),並把連線放入佇列中,此時這個連線的狀態是SYN_RECEIVED。當客戶端返回ACK後(第三次握手),此連線的狀態變為ESTABLISHED。佇列中只有ESTABLISHED狀態的連線能夠交由應用程式處理。
當佇列滿了以後,服務端再收到來自客戶端發起的SYN握手請求時,將不會返回SYN/ACK。比較優雅的處理方法就是不處理這條連線,不返回RST響應結果,讓客戶端重試。
簡單概括為:一個佇列,兩種狀態。
在linux2.2之後:
在底層維護一個SYN_RECEIVED佇列和一個ESTABLISHED佇列,當SYN_RECEIVED佇列中(syn queue)的連線對應的客戶端返回ACK後(三次握手完成),將被移動到ESTABLISHED佇列中。backlog指的是ESTABLISHED佇列(accept queue)的大小。
SYN_RECEIVED 佇列即syn queue大小:由proc/sys/net/ipv4/tcp_max_syn_backlog系統引數指定,預設2048.
ESTABLISHED佇列即accept queue大小:由backlog和/proc/sys/net/core/somaxconn(預設128,或者在 /etc/sysctl.conf 中配置
ss命令檢視下http的佇列狀態:
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
看到監聽的https的佇列狀態:
Send-Q即Accept queue的最大值128.
Recv-Q為0,表示Accept queue中等待被伺服器從accept佇列中拿出的數量。
SYN queue 溢位
Accept queue 溢位
案例:backlog設定過小,accept queue溢位造成的
客戶端connect返回不代表tcp連線建立成功,即雖然客戶端傳送syn請求,得到了syn+ack的響應,然後客戶端傳送ack給伺服器,但是由可能此時accept queue溢位,無法將syn queue的半連線移動到accept queue。所以linux作業系統會直接丟棄後續客戶端的ACK請求。此時客戶端以為連線已經建立,開始傳送資料,無法得到伺服器響應。
案例:backlog設定過大,客戶端關閉連線
backlog設定過大,accept queue佇列擠壓,連線由於超時而被客戶端關閉。
案例:兩次握手後,第三次握手握手失敗
伺服器等待客戶端的ack,然後超時,伺服器會重新發送SYN+ACK給客戶端,重傳次數受net.ipv4.tcp_synack_retries限制。如果這個值設定為1,那麼只會重傳1次,如果這次重傳後客戶端傳送ack仍然失敗,客戶端將阻塞。如果客戶端傳送ack成功,則建立established,三次握手成功呼叫後續recvmsg().