<code>一、TCP標頭 </code>
<code>二、TCP三向交握</code>
<code>三、TCP四次斷開</code>
<code>四、深入了解</code>
一、TCP標頭
<a href="https://s1.51cto.com/oss/201711/22/9f5af19d45c927d23f68636890c1b742.png" target="_blank"></a>
二、TCP三向交握
TCP連接配接建立過程——三次握手
第一次握手:用戶端發送位碼為 SYN = 1(SYN 标志位置位),随機産生初始序列号 Seq = J 的資料包到伺服器。伺服器由 SYN = 1(置位)知道,用戶端要求建立聯機。
第二次握手:伺服器收到請求後要确認聯機資訊,向用戶端發送确認号Ack = (用戶端的Seq +1,J+1),SYN = 1,ACK = 1(SYN,ACK 标志位置位),随機産生的序列号 Seq = K 的資料包。
第三次握手:用戶端收到後檢查 Ack 是否正确,即第一次發送的 Seq +1(J+1),以及位碼ACK是否為1。若正确,用戶端會再發送 Ack = (伺服器端的Seq+1,K+1),ACK = 1,以及序号Seq為伺服器确認号J 的确認包。伺服器收到後确認之前發送的 Seq(K+1) 值與 ACK= 1 (ACK置位)則連接配接建立成功。
經過了這三步之後,用戶端與伺服器端就成功建立起一個 TCP連接配接。這三個步驟統稱為三次握手。
(上面Seq表示序列号,Ack表示确認号,SYN和ACK以及FIN等都是标志位。ACK 被設定為 1表示确認号字段是有效的,如果 ACK為 0,則該段不包含确認資訊。SYN 被用于建立連接配接過程,在連接配接請求中,SYN = 1 和 ACK = 0 表示該段沒有捎帶确認字段。連接配接應答會捎帶一個确認,是以應答時會有 SYN= 1 和 ACK= 1。另外發送ACK無需任何代價,是以我們會看到一旦一個連接配接建立起來,ACK标志總是被置為1)
<a href="https://s5.51cto.com/oss/201711/22/c2312000e6c4d68182e97af27e181fb6.png" target="_blank"></a>
從上圖可以看出,當用戶端調用connect 時,觸發了連接配接請求,向伺服器發送了 SYN J包,這時 connect 進入阻塞狀态;伺服器監聽到連接配接請求,即收到 SYN J包,調用 accept函數接收請求向用戶端發送 SYN K,ACK J+1,這時 accept 進入阻塞狀态,用戶端收到伺服器的 SYN K,ACK J+1之後,這時 connect 傳回,并對 SYN K 進行确認,伺服器收到 ACK K+1時,accept傳回,至此三次握手完畢,連接配接建立。可以得知:用戶端的 connect在三次握手的第二次傳回,而伺服器端的 accept在三次握手的第三次傳回。
為什麼是三次握手:
為了防止已失效的連接配接請求封包段突然又傳送到了服務端,因而産生錯誤
這樣說明“已失效的連接配接請求封包段”的産生在這樣一種情況下:client發出的第一個連接配接請求封包段并沒有丢失,而是在某個網絡結點長時間的滞留了,以緻延誤到連接配接釋放以後的某個時間才到達server。本來這是一個早已失效的封包段。但server收到此失效的連接配接請求封包段後,就誤認為是client再次發出的一個新的連接配接請求。于是就向client發出确認封包段,同意建立連接配接。假設不采用“三次握手”,那麼隻要server發出确認,新的連接配接就建立了。由于現在client并沒有發出建立連接配接的請求,是以不會理睬server的确認,也不會向server發送資料。但server卻以為新的運輸連接配接已經建立,并一直等待client發來資料。這樣,server的很多資源就白白浪費掉了。采用“三次握手”的辦法可以防止上述現象發生。例如剛才那種情況,client不會向server的确認發出确認。server由于收不到确認,就知道client并沒有要求建立連接配接。”
三、TCP四次斷開
TCP連接配接終止過程——四次揮手
由于TCP連接配接是全雙工的,是以每個方向都必須單獨進行關閉,也就是發送方和接收方都需要Fin和Ack。這個原則是當一方完成它的資料發送任務後就能發送一個FIN來種植這個方向的連接配接,收到一個FIN隻意味着這一方向上沒有資料流動,一個TCP連接配接在收到一個FIN後仍能發送資料。首先進行關閉的一方将執行主動關閉,而另一方執行被動關閉。
這裡我們假定用戶端主動關閉(實際上誰先執行主動關閉沒本質差別,通話結束了,誰先挂斷沒啥差別)
用戶端發送一個FIN Seq = M(FIN置位,序号為M)包,用來關閉用戶端到伺服器端的資料傳送。
伺服器端收到這個FIN,它發回一個ACK,确認序号Ack 為收到的序号M+1。
伺服器端關閉與用戶端的連接配接,發送一個FIN Seq = N 給用戶端。
用戶端發回ACK 封包确認,确認序号Ack 為收到的序号N+1。
<a href="https://s2.51cto.com/oss/201711/22/3380d7644a546c430637d5cb727b1336.png" target="_blank"></a>
對于四次揮手,其實仔細看是兩次,因為TCP是全雙工的,必須雙方都關閉才可以,單方會有兩次,共有四次。終止的時候,有一方是被動的,是以看上去就成了四次揮手。
前面有說道,一旦連接配接建立起來,ACK标志位總是被置為1。是以TCP建立連接配接之後,ACK總是被置為1的。
關閉連接配接過程主要看FIN标志位是否置位,ACK在連接配接建立成功之後都是置為1的。
伺服器端先執行示例。
第一次揮手:伺服器端發起主動關閉,FIN置位,Seq = 3022381791;
第二次揮手:用戶端收到FIN後,發回ACK,Ack = Seq + 1 = 3022381792;至此伺服器端的連接配接關閉了,接下來還需要關閉用戶端的。
第三次揮手:用戶端發送FIN,Seq = 4225929031;
第四次揮手:伺服器端收到FIN後,發回ACK,Ack = Seq + 1 = 4225929032.這樣用戶端的連接配接也關閉了。至此全雙工的TCP連接配接關閉。
四、深入了解
如下圖所示,TCP通信過程包括三個步驟:建立TCP連接配接通道(三次握手)、資料傳輸、斷開TCP連接配接通道(四次揮手)。
<a href="https://s3.51cto.com/oss/201711/22/ab6acc8baca95a884f81ed5d9ec6c08b.png" target="_blank"></a>
進一步探究TCP三路握手和四次揮手過程中的狀态變遷以及資料傳輸過程。先看TCP狀态狀态轉換圖。
<a href="https://s5.51cto.com/oss/201711/22/d7ed2d9a775b44d78e165423460d9e46.png" target="_blank"></a>
上半部分是TCP三路握手過程的狀态變遷,下半部分是TCP四次揮手過程的狀态變遷。
1.CLOSED:起始點,在逾時或者連接配接關閉時候進入此狀态,這并不是一個真正的狀态,而是這個狀态圖的假想起點和終點。
2.LISTEN:伺服器端等待連接配接的狀态。伺服器經過 socket,bind,listen 函數之後進入此狀态,開始監聽用戶端發過來的連接配接請求。此稱為應用程式被動打開(等到用戶端連接配接請求)。
3.SYN_SENT:第一次握手發生階段,用戶端發起連接配接。用戶端調用 connect,發送 SYN 給伺服器端,然後進入 SYN_SENT 狀态,等待伺服器端确認(三次握手中的第二個封包)。如果伺服器端不能連接配接,則直接進入CLOSED狀态。
4.SYN_RCVD:第二次握手發生階段,跟 3 對應,這裡是伺服器端接收到了用戶端的 SYN,此時伺服器由 LISTEN 進入 SYN_RCVD狀态,同時伺服器端回應一個 ACK,然後再發送一個 SYN 即 SYN+ACK 給用戶端。狀态圖中還描繪了這樣一種情況,當用戶端在發送 SYN 的同時也收到伺服器端的 SYN請求,即兩個同時發起連接配接請求,那麼用戶端就會從 SYN_SENT 轉換到 SYN_REVD 狀态。
5.ESTABLISHED:第三次握手發生階段,用戶端接收到伺服器端的 ACK 包(ACK,SYN)之後,也會發送一個 ACK 确認包,用戶端進入 ESTABLISHED 狀态,表明用戶端這邊已經準備好,但TCP 需要兩端都準備好才可以進行資料傳輸。伺服器端收到用戶端的 ACK 之後會從 SYN_RCVD 狀态轉移到 ESTABLISHED 狀态,表明伺服器端也準備好進行資料傳輸了。這樣用戶端和伺服器端都是 ESTABLISHED 狀态,就可以進行後面的資料傳輸了。是以 ESTABLISHED 也可以說是一個資料傳送狀态。
上面就是 TCP 三次握手過程的狀态變遷。結合第一張三次握手過程圖,從封包的角度看狀态變遷:SYN_SENT 狀态表示已經用戶端已經發送了 SYN 封包,SYN_RCVD 狀态表示伺服器端已經接收到了 SYN 封包。
下面看看TCP四次揮手過程的狀态變遷。結合第一張四次揮手過程圖來了解。
1.FIN_WAIT_1:第一次揮手。主動關閉的一方(執行主動關閉的一方既可以是用戶端,也可以是伺服器端,這裡以用戶端執行主動關閉為例),終止連接配接時,發送 FIN 給對方,然後等待對方傳回 ACK 。調用 close() 第一次揮手就進入此狀态。
2.CLOSE_WAIT:接收到FIN 之後,被動關閉的一方進入此狀态。具體動作是接收到 FIN,同時發送 ACK。之是以叫 CLOSE_WAIT 可以了解為被動關閉的一方此時正在等待上層應用程式發出關閉連接配接指令。前面已經說過,TCP關閉是全雙工過程,這裡用戶端執行了主動關閉,被動方伺服器端接收到FIN 後也需要調用 close 關閉,這個 CLOSE_WAIT 就是處于這個狀态,等待發送 FIN,發送了FIN 則進入 LAST_ACK 狀态。
3.FIN_WAIT_2:主動端(這裡是用戶端)先執行主動關閉發送FIN,然後接收到被動方傳回的 ACK 後進入此狀态。
4.LAST_ACK:被動方(伺服器端)發起關閉請求,由狀态2 進入此狀态,具體動作是發送 FIN給對方,同時在接收到ACK 時進入CLOSED狀态。
5.CLOSING:兩邊同時發起關閉請求時(即主動方發送FIN,等待被動方傳回ACK,同時被動方也發送了FIN,主動方接收到了FIN之後,發送ACK給被動方),主動方會由FIN_WAIT_1 進入此狀态,等待被動方傳回ACK。
6.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全雙工連接配接的終止;
允許老的重複分節(資料報)在網絡中消逝。
轉自:
http://blog.csdn.net/wenqian1991/article/details/39667131
http://blog.csdn.net/wenqian1991/article/details/40110703
本文轉自MT_IT51CTO部落格,原文連結:http://blog.51cto.com/hmtk520/1984133,如需轉載請自行聯系原作者