1. 程式人生 > >TCP三次握手,4次揮手

TCP三次握手,4次揮手

轉載:http://blog.sina.com.cn/s/articlelist_2754431351_4_1.html

很多網路知識

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

先來看看如何建立連線的。


首先Client端傳送連線請求報文,Server段接受連線後回覆ACK報文,併為這次連線分配資源。Client端接收到ACK報文後也向Server段發生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端所經歷的狀態如下:



【注意】 在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報文。


為什麼需要“三次握手”

            在謝希仁著《計算機網路》第四版中講“三次握手”的目的是“為了防止已失效的連線請求報文段突然又傳送到了服務端,因而產生錯誤”。在另一部經典的《計算機網路》一書中講“三次握手”的目的是為了解決“網路中存在延遲的重複分組”的問題。這兩種不用的表述其實闡明的是同一個問題。
            謝希仁版《計算機網路》中的例子是這樣的,“已失效的連線請求報文段”的產生在這樣一種情況下:client發出的第一個連線請求報文段並沒有丟失,而是在某個網路結點長時間的滯留了,以致延誤到連線釋放以後的某個時間才到達server。本來這是一個早已失效的報文段。但server收到此失效的連線請求報文段後,就誤認為是client再次發出的一個新的連線請求。於是就向client發出確認報文段,同意建立連線。假設不採用“三次握手”,那麼只要server發出確認,新的連線就建立了。由於現在client並沒有發出建立連線的請求,因此不會理睬server的確認,也不會向server傳送資料。但server卻以為新的運輸連線已經建立,並一直等待client發來資料。這樣,server的很多資源就白白浪費掉了。採用“三次握手”的辦法可以防止上述現象發生。例如剛才那種情況,client不會向server的確認發出確認。server由於收不到確認,就知道client並沒有要求建立連線。”。主要目的防止server端一直等待,浪費資源。

為什麼需要“四次揮手”
      那可能有人會有疑問,在tcp連線握手時為何ACK是和SYN一起傳送,這裡ACK卻沒有和FIN一起傳送呢。原因是因為tcp是全雙工模式接收到FIN時意味將沒有資料再發來,但是還是可以繼續傳送資料。

握手,揮手過程中各狀態介紹:

3次握手過程狀態:
LISTEN: 這個也是非常容易理解的一個狀態,表示伺服器端的某個SOCKET處於監聽狀態,可以接受連線了。
SYN_SENT: 當客戶端SOCKET執行CONNECT連線時,它首先發送SYN報文,因此也隨即它會進入到了SYN_SENT狀態,並等待服務端的傳送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已傳送SYN報文。(傳送端)

SYN_RCVD: 這個狀態與SYN_SENT遙想呼應這個狀態表示接受到了SYN報文,在正常情況下,這個狀態是伺服器端的SOCKET在建立TCP連線時的三次握手會話過程中的一箇中間狀態,很短暫,基本上用netstat你是很難看到這種狀態的,除非你特意寫了一個客戶端測試程式,故意將三次TCP握手過程中最後一個 ACK報文不予傳送。因此這種狀態時,當收到客戶端的ACK報文後,它會進入到ESTABLISHED狀態。(伺服器端)
ESTABLISHED:這個容易理解了,表示連線已經建立了。

TCP為什麼需要3次握手與4次揮手

FIN_WAIT_1: 這個狀態要好好解釋一下,其實FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。而這兩種狀態的區別是:FIN_WAIT_1狀態實際上是當SOCKET在ESTABLISHED狀態時,它想主動關閉連線,向對方傳送了FIN報文,此時該SOCKET即進入到FIN_WAIT_1狀態。而當對方迴應ACK報文後,則進入到FIN_WAIT_2狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬上回應ACK報文,所以FIN_WAIT_1狀態一般是比較難見到的,而FIN_WAIT_2狀態還有時常常可以用netstat看到。(主動方)
FIN_WAIT_2:上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2狀態下的SOCKET,表示半連線,也即有一方要求close連線,但另外還告訴對方,我暫時還有點資料需要傳送給你(ACK資訊),稍後再關閉連線。(主動方)
TIME_WAIT表示收到了對方的FIN報文,併發送出了ACK報文,就等2MSL後即可回到CLOSED可用狀態了。如果FIN_WAIT_1狀態下,收到了對方同時帶FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。(主動方)
CLOSING(比較少見): 這種狀態比較特殊,實際情況中應該是很少見,屬於一種比較罕見的例外狀態。正常情況下,當你傳送FIN報文後,按理來說是應該先收到(或同時收到)對方的 ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你傳送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什麼情況下會出現此種情況呢?其實細想一下,也不難得出結論:那就是如果雙方几乎在同時close一個SOCKET的話,那麼就出現了雙方同時傳送FIN報文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET連線
CLOSE_WAIT: 這種狀態的含義其實是表示在等待關閉。怎麼理解呢?當對方close一個SOCKET後傳送FIN報文給自己,你係統毫無疑問地會迴應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有資料傳送給對方,如果沒有的話,那麼你也就可以 close這個SOCKET,傳送FIN報文給對方,也即關閉連線。所以你在CLOSE_WAIT狀態下,需要完成的事情是等待你去關閉連線。(被動方)
LAST_ACK: 這個狀態還是比較容易好理解的,它是被動關閉一方在傳送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,也即可以進入到CLOSED可用狀態了。(被動方)

CLOSED: 表示連線中斷。

TCP為什麼需要3次握手與4次揮手