1. 程式人生 > >TCP三次握手四次揮手過程詳解

TCP三次握手四次揮手過程詳解

TCP頭部: 其中 ACK   SYN  序號  這三個部分在以下會用到,它們的介紹也在下面。

暫時需要的資訊有:

ACK : TCP協議規定,只有ACK=1時有效,也規定連線建立後所有傳送的報文的ACK必須為1

SYN(SYNchronization) : 在連線建立時用來同步序號。當SYN=1而ACK=0時,表明這是一個連線請求報文。對方若同意建立連線,則應在響應報文中使SYN=1和ACK=1. 因此,  SYN置1就表示這是一個連線請求或連線接受報文。

FIN (finis)即完,終結的意思, 用來釋放一個連線。當 FIN = 1 時,表明此報文段的傳送方的資料已經發送完畢,並要求釋放連線。

三次握手的過程:

首先由Client發出請求連線即 SYN=1 ACK=0  (請看頭欄位的介紹), TCP規定SYN=1時不能攜帶資料,但要消耗一個序號,因此宣告自己的序號是 seq=x

然後 Server 進行回覆確認,即 SYN=1 ACK=1 seq=y, ack=x+1,

再然後 Client 再進行一次確認,但不用SYN 了,這時即為 ACK=1, seq=x+1, ack=y+1.

然後連線建立,為什麼要進行三次握手呢(兩次確認)。

下面是釋放連線的過程:


當客戶A 沒有東西要傳送時就要釋放 A 這邊的連線,A會發送一個報文(沒有資料),其中 FIN 設定為1,  伺服器B收到後會給應用程式一個信,這時A那邊的連線已經關閉,即A不再發送資訊(但仍可接收資訊)。  A收到B的確認後進入等待狀態,等待B請求釋放連線, B資料傳送完成後就向A請求連線釋放,也是用FIN=1 表示, 並且用 ack = u+1(如圖), A收到後回覆一個確認資訊,並進入 TIME_WAIT 狀態, 等待 2MSL 時間。

為什麼要等待呢?

為了這種情況: B向A傳送 FIN = 1 的釋放連線請求,但這個報文丟失了, A沒有接到不會發送確認資訊, B 超時會重傳,這時A在 WAIT_TIME 還能夠接收到這個請求,這時再回復一個確認就行了。(A收到 FIN = 1 的請求後 WAIT_TIME會重新記時)

另外伺服器B存在一個保活狀態,即如果A突然故障宕機了,那B那邊的連線資源什麼時候能釋放呢?  就是保活時間到了後,B會發送探測資訊, 以決定是否釋放連線。

【注意】中斷連線端可以是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報文。