面試官:你說一下TCP為什么需要三次握手和四次揮手?
TCP協議是一種面向連接的、可靠的、基于字節流的運輸層通信協議,TCP是全雙工模式,需要三次握手建立連接,四次揮手關閉連接。
三次握手
三次握手(Three-way Handshake)是指建立一個 TCP 連接時,需要客戶端和服務器總共發送3個報文。
三次握手的目的是連接服務器指定端口,建立 TCP 連接,并同步連接雙方的序列號和確認號,交換 TCP 窗口大小信息。在 socket 編程中,客戶端執行 connect() 時。將觸發三次握手。 三次握手過程如下:
圖片
剛開始客戶段和服務器端都處于CLOSED(關閉)狀態,隨后服務器進程處于LISTEN(收聽)狀態,等待客戶端的連接請求。
- 第一次握手(發送SYN):客戶端向服務器發出連接請求,附帶客戶端序列號seq,然后進入 SYN_SENT(同步已發送) 狀態,等待服務器的確認。
- 第二次握手(發送SYN+ACK):服務器收到連接請求,同意建立連接,然后向客戶段發送確認連接信息,附帶向客戶端連接請求,此時服務器進入 SYN_RCVD(同步收到) 狀態。
- 第三次握手(發送ACK):客戶端收到服務器的確認連接信息,向服務器發送確認連接,此時TCP連接已經建立,客戶端進入 ESTABLISHED 狀態。當服務器收到客戶端發送的確認報文后也會進入 ESTABLISHED 狀態,完成三次握手。
為什么需要三次握手,而不是二次握手?三次握手的目的是為了防止已失效的連接請求突然又傳送到了服務端,而產生錯誤。
假設采用兩次握手建立連接,客戶端第一次向服務端發送建立連接請求,因為網絡延遲的原因,一直沒有到達服務器。于是客戶端再次向服務端重新發送建立連接請求,這次服務端收到連接請求后,向客戶端回復確認,建立連接。但是這時網絡延遲恢復,服務端又收到客戶端第一次發送的連接請求,服務端認為客戶端又發起了一次連接,再次回復確認,又建立了一個連接。
服務端認為有兩個連接,客戶端認為有一個連接,造成數據狀態不一致。
至于為什么不像斷開連接一樣采用四次握手,因為服務端把確認連接請求和向客戶端發送的建立連接請求合并成一次請求,發送給客戶端了。
四次揮手
四次揮手是指斷開一個TCP連接時,需要客戶端和服務端總共發送4個報文以確認連接的斷開。 四次揮手的過程如下:
圖片
- 第一次揮手(發送FIN):當通信的一方完成數據發送任務,需要關閉連接時,它會發送一個FIN(結束)報文段,進入FIN_WAIT_1 狀態。無論是客戶端還是服務端,任何一方都可以主動發起關閉連接的請求。
- 第二次揮手(發送ACK):服務端收到FIN報文段后,發送一個ACK報文段作為回應,并進入CLOSE-WAIT狀態??蛻舳耸盏紸CK后,進入FIN-WAIT-2狀態。這時候已經斷開了客戶端與服務端的連接,服務端依然可以繼續向客戶端發送數據。
- 第三次揮手(發送FIN):服務器端完成數據傳輸后,發送一個FIN報文段,請求關閉連接,進入LAST-ACK狀態。
- 第四次揮手(發送ACK):客戶端收到服務器的 FIN 包后,發送ACK報文段作為回應,并進入TIME-WAIT狀態。經過 2MSL 后,客戶端才進入 CLOSED 狀態。服務器端收到客戶端的確認包 ACK 后進入CLOSED 狀態,連接被最終關閉。
為什么需要四次揮手?
由于TCP連接是全雙工的,即數據可以在兩個方向上流動,因此每個方向都必須要單獨進行關閉,關閉一個方向上的連接需要一次請求和一次確認,最終需要四次請求。
為什么不能是三次,不能像建立連接那樣把第二次和第三次合并成一次?
因為在第二次請求時服務端向客戶端發送確認關閉連接,此時服務端可能還有一些數據沒有傳輸完成,需要繼續向客戶端發送數據,不能跟合并服務器向客戶端發送的關閉連接請求,所以需要拆分成兩個連接請求。