1. 程式人生 > >通俗易懂地講解TCP建立連線的三次握手和釋放連線的四次揮手

通俗易懂地講解TCP建立連線的三次握手和釋放連線的四次揮手

TCP建立連線時,為什麼要進行三次揮手?

  每一次TCP連線都需要三個階段:連線建立、資料傳送和連線釋放。三次握手就發生在連線建立階段。 在謝希仁著《計算機網路》第四版中講三次握手的目的是為了防止已失效的連線請求報文段突然又傳送到了服務端,因而產生錯誤。在另一部經典的《計算機網路》一書中講三次握手的目的是為了解決網路中存在延遲的重複分組的問題。   這兩種不用的表述其實闡明的是同一個問題。

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

  這個例子很清晰的闡釋了三次握手對於建立可靠連線的意義。在Google Groups的TopLanguage中看到一帖討論TCP三次握手覺得很有意思。貼主提出的問題,在眾多回復中,有一條回覆寫道:這個問題的本質是, 通道不可靠, 但是通訊雙發需要就某個問題達成一致. 而要解決這個問題, 無論你在訊息中包含什麼資訊, 三次通訊是理論上的最小值. 所以三次握手不是TCP本身的要求, 而是為了滿足"在不可靠通道上可靠地傳輸資訊"這一需求所導致的. 請注意這裡的本質需求,通道不可靠, 資料傳輸要可靠. 三次達到了, 那後面你想接著握手也好, 發資料也好, 跟進行可靠資訊傳輸的需求就沒關係了. 因此,如果通道是可靠的, 即無論什麼時候發出訊息, 對方一定能收到, 或者你不關心是否要保證對方收到你的訊息, 那就能像UDP那樣直接傳送訊息就可以了. 。這可視為對三次握手目的的另一種解答思路。

 

舉個打電話的例子

  A : 你好我是A,你聽得到我在說話嗎

  B : 聽到了,我是B,你聽到我在說話嗎

  A : 嗯,聽到了

  建立連線,開始聊天!

 



 

為什麼TCP協議終止連結要四次?

1、當主機A確認傳送完資料且知道B已經接受完了,想要關閉傳送資料口(當然確認訊號還是可以發),就會發FIN給主機B。

2、主機B收到A傳送的FIN,表示收到了,就會發送ACK回覆。

3、但這是B可能還在傳送資料,沒有想要關閉資料口的意思,所以FIN與ACK不是同時傳送的,而是等到B資料傳送完了,才會傳送FIN給主機A。

4、A收到B發來的FIN,知道B的資料也傳送完了,回覆ACK, A等待2MSL以後,沒有收到B傳來的任何訊息,知道B已經收到自己的ACK了,A就關閉連結,B也關閉連結了。

 

A為什麼等待2MSL,從TIME_WAIT到CLOSE?

 在Client傳送出最後的ACK回覆,但該ACK可能丟失。Server如果沒有收到ACK,將不斷重複傳送FIN片段。所以Client不能立即關閉,它必須確認Server接收到了該ACK。Client會在傳送出ACK之後進入到TIME_WAIT狀態。Client會設定一個計時器,等待2MSL的時間。如果在該時間內再次收到FIN,那麼Client會重發ACK並再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。MSL指一個片段在網路中最大的存活時間,2MSL就是一個傳送和一個回覆所需的最大時間。如果直到2MSL,Client都沒有再次收到FIN,那麼Client推斷ACK已經被成功接收,則結束TCP連線。

 

這個網上轉載的例子不錯:

三次握手:
A:“喂,你聽得到嗎?”A->SYN_SEND

B:“我聽得到呀,你聽得到我嗎?”應答與請求同時發出 B->SYN_RCVD | A->ESTABLISHED

A:“我能聽到你,今天balabala……”B->ESTABLISHED

四次揮手:
A:“喂,我不說了。”A->FIN_WAIT1

B:“我知道了。等下,上一句還沒說完。Balabala…..”B->CLOSE_WAIT | A->FIN_WAIT2

B:”好了,說完了,我也不說了。”B->LAST_ACK

A:”我知道了。”A->TIME_WAIT | B->CLOSED

A等待2MSL,保證B收到了訊息,否則重說一次”我知道了”,A->CLOSED