[小端日記] - 如何理解TCP的四次揮手


       當客戶端和服務器經過三次握手創建了TCP鏈接之後,當數據傳送完畢,確定是要斷開TCP鏈接的啊。那對於TCP的斷開鏈接,這裏就有了神祕的「四次揮手」。
前端


第一次揮手:服務器

Client (可使客戶端,也能夠是服務器端),設置Sequence Number和Acknowledgment Number,向 Server發送一個FIN報文段;此時,Client 進入FIN_WAIT_1狀態;這表示 Client 沒有數據要發送給 Server了;網絡

客戶端發送第一次揮手後,就不能在向 服務端發送數據了。前端工程師

第二次揮手:併發

Server 收到了 Client 發送的FIN報文段,向 Client 回一個ACK報文段,Acknowledgment Number 爲 Sequence Number 加 1;Client 進入 FIN_WAIT_2 狀態;Server 告訴 Client ,我「贊成」你的關閉請求;cdn

Server 第一次響應後,還能夠繼續向 Client 發送數據,這裏只是告訴 Client ,我收到你發送的關閉請求。blog

第三次揮手資源

Server 向 Client 發送 FIN 報文段,請求關閉鏈接,同時 Server 進入 CLOSE_WAIT 狀態;同步

當 Server 的數據響應完成後,再告訴 Client,我這邊也能夠關閉請求了, 這時
Server 就不能再向 Client 發送數據了
it

第四次揮手

Client 收到 Server 發送的 FIN 報文段,向 Server 發送 ACK 報文段,而後 Client 進入
TIME_WAIT 狀態;Server 收到 Client 的 ACK 報文段之後,就關閉鏈接;此時,Client
等待2MSL後依然沒有收到回覆,則證實 Server 端已正常關閉,那好,Client 也能夠關閉鏈接了。


問:爲何鏈接的時候是三次握手,關閉的時候倒是四次握手? 

答:由於當Server端收到Client端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步握手。  

問:爲何TIME_WAIT狀態須要通過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

答:雖然按道理,四個報文都發送完畢,咱們能夠直接進入CLOSE狀態了,可是咱們必須假象網絡是不可靠的,有能夠最後一個ACK丟失。因此TIME_WAIT狀態就是用來重發可能丟失的ACK報文。在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鏈接。  

問:爲何不能用兩次握手進行鏈接?  

答:3次握手完成兩個重要的功能,既要雙方作好發送數據的準備工做(雙方都知道彼此已準備好),也要容許雙方就初始序列號進行協商,這個序列號在握手過程當中被髮送和確認。 如今把三次握手改爲僅須要兩次握手,死鎖是可能發生的。做爲例子,考慮計算機S和C之間的通訊,假定C給S發送一個鏈接請求分組,S收到了這個分組,併發 送了確認應答分組。按照兩次握手的協定,S認爲鏈接已經成功地創建了,能夠開始發送數據分組。但是,C在S的應答分組在傳輸中被丟失的狀況下,將不知道S 是否已準備好,不知道S創建什麼樣的序列號,C甚至懷疑S是否收到本身的鏈接請求分組。在這種狀況下,C認爲鏈接還未創建成功,將忽略S發來的任何數據分 組,只等待鏈接確認應答分組。而S在發出的分組超時後,重複發送一樣的分組。這樣就造成了死鎖。 

問:若是已經創建了鏈接,可是客戶端忽然出現故障了怎麼辦?  

TCP還設有一個保活計時器,顯然,客戶端若是出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會從新復位這個計時器,時間一般是設置爲2小時,若兩小時尚未收到客戶端的任何數據,服務器就會發送一個探測報文段,之後每隔75秒鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉鏈接。 


結束語: 作一個努力、勤奮、主動的前端工程師

相關文章
相關標籤/搜索