TCP狀態轉換圖

如下圖所示,TCP通信過程包括三個步驟:建立TCP連接通道(三次握手)、數據傳輸、斷開TCP連接通道(四次揮手)。
                                      
TCP狀態轉換圖
這裏進一步探究TCP三路握手和四次揮手過程中的狀態變遷以及數據傳輸過程。先看TCP狀態狀態轉換圖。
TCP狀態轉換圖
                                                                                     
上半部分是TCP三路握手過程的狀態變遷,下半部分是TCP四次揮手過程的狀態變遷。
CLOSED:起始點,在超時或者連接關閉時候進入此狀態,這並不是一個真正的狀態,而是這個狀態圖的假想起點和終點。LISTEN:服務器端等待連接的狀態。服務器經過 socket,bind,listen 函數之後進入此狀態,開始監聽客戶端發過來的連接請求。此稱爲應用程序被動打開(等到客戶端連接請求)。SYN_SENT:第一次握手發生階段,客戶端發起連接。客戶端調用 connect,發送 SYN 給服務器端,然後進入 SYN_SENT 狀態,等待服務器端確認(三次握手中的第二個報文)。如果服務器端不能連接,則直接進入CLOSED狀態。SYN_RCVD:第二次握手發生階段,跟 3 對應,這裏是服務器端接收到了客戶端的 SYN,此時服務器由 LISTEN 進入 SYN_RCVD狀態,同時服務器端迴應一個 ACK,然後再發送一個 SYN 即 SYN+ACK 給客戶端。狀態圖中還描繪了這樣一種情況,當客戶端在發送 SYN 的同時也收到服務器端的 SYN請求,即兩個同時發起連接請求,那麼客戶端就會從
SYN_SENT 轉換到 SYN_REVD 狀態。ESTABLISHED:第三次握手發生階段,客戶端接收到服務器端的 ACK 包(ACK,SYN)之後,也會發送一個 ACK 確認包,客戶端進入 ESTABLISHED 狀態,表明客戶端這邊已經準備好,但TCP 需要兩端都準備好纔可以進行數據傳輸。服務器端收到客戶端的 ACK 之後會從 SYN_RCVD 狀態轉移到 ESTABLISHED 狀態,表明服務器端也準備好進行數據傳輸了。這樣客戶端和服務器端都是
ESTABLISHED 狀態,就可以進行後面的數據傳輸了。所以 ESTABLISHED 也可以說是一個數據傳送狀態。上面就是 TCP 三次握手過程的狀態變遷。結合第一張三次握手過程圖,從報文的角度看狀態變遷:SYN_SENT 狀態表示已經客戶端已經發送了 SYN 報文,SYN_RCVD 狀態表示服務器端已經接收到了 SYN 報文。

下面看看TCP四次揮手過程的狀態變遷。結合第一張四次揮手過程圖來理解。
FIN_WAIT_1:第一次揮手。主動關閉的一方(執行主動關閉的一方既可以是客戶端,也可以是服務器端,這裏以客戶端執行主動關閉爲例),終止連接時,發送 FIN 給對方,然後等待對方返回 ACK 。調用 close() 第一次揮手就進入此狀態。CLOSE_WAIT:接收到FIN 之後,被動關閉的一方進入此狀態。具體動作是接收到 FIN,同時發送 ACK。之所以叫 CLOSE_WAIT 可以理解爲被動關閉的一方此時正在等待上層應用程序發出關閉連接指令。前面已經說過,TCP關閉是全雙工過程,這裏客戶端執行了主動關閉,被動方服務器端接收到FIN
後也需要調用 close 關閉,這個 CLOSE_WAIT 就是處於這個狀態,等待發送 FIN,發送了FIN 則進入 LAST_ACK 狀態。FIN_WAIT_2:主動端(這裏是客戶端)先執行主動關閉發送FIN,然後接收到被動方返回的 ACK 後進入此狀態。LAST_ACK:被動方(服務器端)發起關閉請求,由狀態2 進入此狀態,具體動作是發送 FIN給對方,同時在接收到ACK 時進入CLOSED狀態。CLOSING:兩邊同時發起關閉請求時(即主動方發送FIN,等待被動方返回ACK,同時被動方也發送了FIN,主動方接收到了FIN之後,發送ACK給被動方),主動方會由FIN_WAIT_1 進入此狀態,等待被動方返回ACK。TIME_WAIT:從狀態變遷圖會看到,四次揮手操作最後都會經過這樣一個狀態然後進入CLOSED狀態。共有三個狀態會進入該狀態由CLOSING進入:同時發起關閉情況下,當主動端接收到ACK後,進入此狀態,實際上這裏的同時是這樣的情況:客戶端發起關閉請求,發送FIN之後等待服務器端迴應ACK,但此時服務器端同時也發起關閉請求,也發送了FIN,並且被客戶端先於ACK接收到。由FIN_WAIT_1進入:發起關閉後,發送了FIN,等待ACK的時候,正好被動方(服務器端)也發起關閉請求,發送了FIN,這時客戶端接收到了先前ACK,也收到了對方的FIN,然後發送ACK(對對方FIN的迴應),與CLOSING進入的狀態不同的是接收到FIN和ACK的先後順序。由FIN_WAIT_2進入:這是不同時的情況,主動方在完成自身發起的主動關閉請求後,接收到了對方發送過來的FIN,然後迴應 ACK。下面來看看這個看似有點多餘的TIME_WAIT狀態:從上面進入TIME_WAIT狀態的三個狀態動作來看(可以直接看狀態變遷圖)都是主動方最後迴應一個ACK(CLOSING實際上前面的那個FIN_WAIT_1狀態就已經迴應了ACK)。
先考慮這樣的一個情況,假如這個最後迴應的ACK丟失了,也就是服務器端接收不到這個ACK,那麼服務器將繼續發送它最終的那個FIN,因此客戶端必須維護狀態信息(TIME_WAIT)允許它重發最後的那個ACK。如果沒有這個TIME_WAIT狀態,客戶端處於CLOSED狀態(開頭就說了CLOSED狀態實際並不存在,是我們爲了方便描述假想的),那麼客戶端將響應RST,服務器端收到後會將該RST分節解釋成一個錯誤,也就不能實現最後的全雙工關閉了(可能是主動方單方的關閉)。所以要實現TCP全雙工連接的正常終止(兩方都關閉連接),必須處理終止過程中四個分節任何一個分節的丟失情況,那麼主動關閉連接的主動端必須維持TIME_WAIT狀態,最後一個迴應ACK的是主動執行關閉的那端。從變遷圖可以看出,如果沒有TIME_WAIT狀態,我們將沒有任何機制來保證最後一個ACK能夠正常到達。前面的FIN,ACK正常到達均有相應的狀態對應。
還有這樣一種情況,如果目前的通信雙方都已經調用了 close(),都到達了CLOSED狀態,沒有TIME_WAIT狀態時,會出現這樣一種情況,現在有一個新的連接被建立起來,使用的IP地址和端口和這個先前到達了CLOSED狀態的完全相同,假定原先的連接中還有數據報殘存在網絡之中,這樣新的連接建立以後傳輸的數據極有可能就是原先的連接的數據報,爲了防止這一點,TCP不允許從處於TIME_WAIT狀態的socket
建立一個連接。處於TIME_WAIT狀態的 socket 在等待了兩倍的MSL時間之後,將會轉變爲CLOSED狀態。這裏TIME_WAIT狀態持續的時間是2MSL(MSL是任何IP數據報能夠在因特網中存活的最長時間),足以讓這兩個方向上的數據包被丟棄(最長是2MSL)。通過實施這個規則,我們就能保證每成功建立一個TCP連接時,來自該連接先前化身的老的重複分組都已經在網絡中消逝了。
  綜上來看:TIME_WAIT存在的兩個理由就是
可靠地實現TCP全雙工連接的終止;允許老的重複分節(數據報)在網絡中消逝。


本文來自 selfimpr1991 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/wenqian1991/article/details/40110703?utm_source=copy

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章