深入理解TCP 3次握手

 戳藍字「TopCoder」關注我們哦!

說起TCP的三次握手,大多數小夥伴多少都聽說過一些,因此本文不再贅述三次握手的詳細流程,而是重點關注三次握手中半連接隊列和全連接隊列流程,以及二者隊列滿了時的處理機制,最後分析下常見的三次握手的問題,這些問題大都也是和半連接隊列和全連接隊列相關的。

三次握手

TCP三次握手大致流程如下:

  1. client 發送 syn 到server 發起握手;

  2. server 收到 syn後回覆syn+ack給client;

  3. client 收到syn+ack後,回覆server一個ack表示收到了server的syn+ack,這時表示連接建立完成。

三次握手對應抓包如下:

半連接隊列/全連接隊列

上面說的TCP三次握手並沒有提到半連接隊列和全連接隊列,其實三次握手流程中還涉及到半連接和全連接隊列之間的流轉動作,對應的流程如下:

  1. client 發送 syn 到server 發起握手;

  2. server 收到 syn後回覆syn+ack給client,同時server端會將連接放到半連接隊列;

  3. client 收到syn+ack後,回覆server一個ack表示收到了server的syn+ack,這時表示連接建立完成,此時server端會將連接放到全連接隊列(這時連接已經建立OK了,只不過進程還無感知,進程需要主動調用accept之後拿到該連接信息,並分配對應fd之後就可以進行IO讀寫操作了)。

如上圖所示,這裏有兩個隊列:syns queue(半連接隊列);accept queue(全連接隊列)。

隊列滿時處理機制

半連接隊列和全連接隊列滿時有以下3種場景:

  • 半連接滿了,全連接未滿:當半連接滿了時,默認處理機制是,TCP忽略請求,也不發送RST,爲什麼要這麼處理呢?因爲這樣做是暫時的,客戶端將重新發送SYN,期望不久就能得到服務。假如服務端響應一個RST,客戶端的connect就會返回錯誤,而不是讓重傳機制來處理,這樣客戶無法區分SYN的RST是因爲"該端口沒有在監聽"還是"該端口在監聽,只不過它的隊列滿了"

  • 半連接未滿,全連接滿了:當全連接隊列滿了時,再往全連接隊列塞時操作系統會按照 tcp_abort_on_overflow 的指示執行,默認爲0表示扔掉client發過來的ack(在server端認爲連接還沒建立起來),爲1表示發送一個reset包給client。

  • 半連接和全連接都滿了:相當於集中了以上所述的2種場景的最差場景,新連接默認不處理讓TCP重傳機制進行重試,往全連接隊列塞時默認按照 tcp_abort_on_overflow 指示來執行。

半連接/全連接隊列的大小到底是多少呢?

準確來說,全連接隊列的大小取決於:min(backlog, somaxconn) . backlog是在socket創建的時候傳入的,somaxconn是一個os級別的系統參數,也就是/proc/sys/net/core/somaxconn的大小。半連接隊列的大小取決於:max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)。不同版本的os會有些差異。

常見問題分析

  • 網站服務中常見的syn floods攻擊,就是針對半連接隊列攻擊的,攻擊客戶端不停地新建連接,但是它只、不會處理接收到的第二步的響應結果,導致server端半連接隊列滿了而無法處理正常進來的建立連接請求。

  • 壓測場景中可能存在的連接建立不上問題,可能是默認的backlog較小導致,這樣很容易導致隊列滿了,然後忽略該請求報文,客戶端遲遲建立不上連接。

  • 全連接隊列攻擊,攻擊客戶端只連接而不進行發送數據的一種攻擊方式,如果服務端使用的是一個線程一個連接的處理方式,會白白佔用很多線程資源;如果是NIO處理方式,雖然不用多佔用線程資源,但是也是會白白佔用fd資源的。

最後我們想一下,TCP爲什麼需要3次握手呢?

一句話總結就是:3次握手保證了連接的可靠性與效率。3次握手過程中,會交換各自的一些信息,比如窗口大小、初始報文序號等,如果只有2次握手,不能保證客戶端一定能收到服務端的響應報文(SYN+ACK)。

 推薦閱讀 


歡迎小夥伴關注【TopCoder】閱讀更多精彩好文。

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