您好,登錄后才能下訂單哦!
如下圖所示,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
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。