1. 程式人生 > >網路程式設計理論知識(三)TCP三次握手與四次揮手最簡潔易懂的解釋

網路程式設計理論知識(三)TCP三次握手與四次揮手最簡潔易懂的解釋

建立TCP需要三次握手才能建立,而斷開連線則需要四次握手。整個過程如下圖所示:

建立連線的過程:
TCP 連線是通過三次握手進行初始化的。三次握手的目的是同步連線雙方的序列號和確認號並交換 TCP 視窗大小資訊。以下步驟概述了通常情況下客戶端計算機聯絡伺服器計算機的過程:
1. 客戶端向伺服器傳送一個SYN置位的TCP報文,其中包含連線的初始序列號x和一個視窗大小(表示客戶端上用來儲存從伺服器傳送來的傳入段的緩衝區的大小)。
2. 伺服器收到客戶端傳送過來的SYN報文後,向客戶端傳送一個SYN和ACK都置位的TCP報文,其中包含它選擇的初始序列號y、對客戶端的序列號的確認x+1和一個視窗大小(表示伺服器上用來儲存從客戶端傳送來的傳入段的緩衝區的大小)。
3. .客戶端接收到伺服器端返回的SYN+ACK報文後,向伺服器端返回一個確認號y+1和序號x+1的ACK報文,一個標準的TCP連線完成。


斷開連線的過程:


【注意】中斷連線端可以是Client端,也可以是Server端。

假設Client端發起中斷連線請求,也就是傳送FIN報文。Server端接到FIN報文後,意思是說"我Client端沒有資料要發給你了",但是如果你還有資料沒有傳送完成,則不必急著關閉Socket,可以繼續傳送資料。所以你先發送ACK,"告訴Client端,你的請求我收到了,但是我還沒準備好,請繼續你等我的訊息"。這個時候Client端就進入FIN_WAIT狀態,繼續等待Server端的FIN報文。當Server端確定資料已傳送完成,則向Client端傳送FIN報文,"告訴Client端,好了,我這邊資料發完了,準備好關閉連線了"。Client端收到FIN報文後,"就知道可以關閉連線了,但是他還是不相信網路,怕Server端不知道要關閉,所以傳送ACK後進入TIME_WAIT狀態,如果Server端沒有收到ACK則可以重傳。“,Server端收到ACK後,"就知道可以斷開連線了"。Client端等待了2MSL後依然沒有收到回覆,則證明Server端已正常關閉,那好,我Client端也可以關閉連線了。Ok,TCP連線就這樣關閉了!

整個過程Client端所經歷的狀態:


Server端所經歷的過程:


【注意】 在TIME_WAIT狀態中,如果TCP client端最後一次傳送的ACK丟失了,它將重新發送。TIME_WAIT狀態中所需要的時間是依賴於實現方法的。典型的值為30秒、1分鐘和2分鐘。等待之後連線正式關閉,並且所有的資源(包括埠號)都被釋放。

【問題1】為什麼連線的時候是三次握手,關閉的時候卻是四次握手?
答:因為當Server端收到Client端的SYN連線請求報文後,可以直接傳送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連線時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端所有的報文都發送完了,我才能傳送FIN報文,因此不能一起傳送。故需要四步握手。

【問題2】為什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
答:雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網路是不可靠的,有可以最後一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。

【問題3】為什麼不能用兩次握手進行連線?
答:3次握手完成兩個重要的功能,既要雙方做好傳送資料的準備工作(雙方都知道彼此已準備好),也要允許雙方就初始序列號進行協商,這個序列號在握手過程中被髮送和確認。
       現在把三次握手改成僅需要兩次握手,死鎖是可能發生的。作為例子,考慮計算機S和C之間的通訊,假定C給S傳送一個連線請求分組,S收到了這個分組,併發 送了確認應答分組。按照兩次握手的協定,S認為連線已經成功地建立了,可以開始傳送資料分組。可是,C在S的應答分組在傳輸中被丟失的情況下,將不知道S 是否已準備好,不知道S建立什麼樣的序列號,C甚至懷疑S是否收到自己的連線請求分組。在這種情況下,C認為連線還未建立成功,將忽略S發來的任何資料分 組,只等待連線確認應答分組。而S在發出的分組超時後,重複傳送同樣的分組。這樣就形成了死鎖。