圖片來源自網絡
“揮手”是爲了終止連接,TCP四次揮手的流程圖如下:
- 第一次揮手:Client發送一個FIN,用來關閉Client到Server的數據傳送,Client進入FIN_WAIT_1狀態;
- 客戶端發送報文,完成信號FIN=1,序號seq=u
- 進入完成FIN_WAIT_1狀態,等待服務端確認
- 第二次揮手:Server收到FIN後,發送一個ACK給Client,確認序號爲收到序號+1(與SYN相同,一個FIN佔用一個序號),Server進入CLOSE_WAIT狀態
- 服務端發送確認報文,確認信號ACK=1,序號=v,確認序號ack=u+1
- 此時服務端就進入Close-wait狀態,半關閉狀態
- 此時客戶端就進入FIN-wait狀態,終止等待狀態,等待服務器發送釋放連接報文
- 這裏有可能服務端還會持續完成數據傳送。因此seq值會改變
- 第三次揮手:Server發送一個FIN,用來關閉Server到Client的數據傳送,Server進入LAST_ACK狀態。
- 服務端發送數據完成報文,完成信號FIN=1,確認信號ACK=1,序號seq=w,確認信號ack=u+1
- 此時服務端進入最後確認狀態,等待客戶端發送確認
- 第四次揮手:Client收到FIN後,Client進入TIME_WAIT狀態,接着發送一個ACK給Server,確認序號爲收到序號+1,Server進入CLOSED狀態,完成四次揮手。
- 客戶端確認報文,確認信號ACK=1,序號seq = u+1,確認序號ack=w+1
- 此時服務端進入關閉狀態
- 此時客戶端進入TIME-WAIT狀態,時間等待狀態,還未釋放連接,必須經過2*MSL的時間纔會進行釋放。RFC定義爲兩分鐘,而Linux的時間爲30秒
- 爲什麼會有TIME_WAIT狀態
- 確保有足夠時間讓對方(上圖爲server端)收到ACK包
- 避免新舊連接混繞
- 爲什麼需要四次握手才能斷開連接
- 因爲全雙工,發送方和接收方都需要FIN報文和ACK報文
- 服務器出現大量CLOSE_WAIT狀態的原因
- 對方關閉socker連接,我方忙於讀或寫,沒有及時關閉連接
- 檢查代碼,特別是釋放資源的代碼
- 檢查配置,特別是處理請求的線程配置