TCP狀態(tài)轉移
在前一篇文章【面試必考】TCP協議“三次握手”與“四次揮手”已經介紹了TCP協議的三次握手和四次揮手??偟膩碚f,TCP通信過程包括三個步驟:建立TCP連接(三次握手)、數據傳輸、終止TCP連接(四次揮手)。但是在這個通信過程中,有非常復雜的狀態(tài)問題,下面就來了解一下進行TCP協議通信時候的狀態(tài)轉移。
TCP協議根據連接時接收到報文的不同類型,采取相應動作也不同,還要處理各個狀態(tài)的關系,如當收到握手報文時候、超時的時候、用戶主動關閉的時候等都需要不一樣的狀態(tài)去采取不一樣的處理。在LwIP中,為了實現TCP協議的狀態(tài)描述,定義了11種連接時候的狀態(tài):
1static const char *const tcp_state_str[] = {
2 "CLOSED", //關閉狀態(tài)(無連接)
3 "LISTEN", //監(jiān)聽狀態(tài)
4 "SYN_SENT", //已發(fā)起請求連接(等待確認)
5 "SYN_RCVD", //已收到請求連接
6 "ESTABLISHED",//穩(wěn)定連接狀態(tài)
7 "FIN_WAIT_1", //單向請求終止連接狀態(tài)
8 "FIN_WAIT_2", //對方已應答請求終止連接
9 "CLOSE_WAIT", //等待終止連接
10 "CLOSING", //兩端同時關閉
11 "LAST_ACK", //服務器等待對方接受關閉
12 "TIME_WAIT" //關閉成功(2MSL等待狀態(tài))
13};
LISTEN:表示監(jiān)聽狀態(tài)。服務器調用了listen函數進入監(jiān)聽狀態(tài),客戶端可以開始進行連接了。SYN_SENT:表示客戶端已經發(fā)送了SYN報文請求連接(同時在等待服務器的確認)。當客戶端調用connect函數發(fā)起連接時,首先發(fā)SYN給服務端,然后自己進入SYN_SENT狀態(tài),并等待服務端發(fā)送ACK+SYN報文(握手應答報文)進行確認。SYN_RCVD:在每一個 TCP 連接建立時,都要進行三次握手,這個狀態(tài)表示服務器接收到客戶端發(fā)來的同步報文段(第一次握手),并且向客戶端發(fā)送了確認同步報文段(第二次握手)之后的狀態(tài),在這個狀態(tài)時,其實連接已經經歷了兩次握手。ESTABLISHED:這個狀態(tài)是處于穩(wěn)定連接狀態(tài),建立連接的TCP協議兩端的主機都是處于這個狀態(tài),它們相互知道彼此的窗口大小、序列號、最大報文段等信息。FIN_WAIT_1與FIN_WAIT_2:處于這個狀態(tài)一般都是客戶端主機單向請求終止連接,然后主機等待服務器的回應,而如果服務器產生應答,則主機狀態(tài)轉移為FIN_WAIT_2,此時<客戶端 -> 服務器>方向上的TCP連接就斷開,但是<服務器 -> 客戶端>方向上的連接還是存在的。此處有一個注意的地方:如果主機處于FIN_WAIT_2狀態(tài),說明主機已經發(fā)出了FIN報文段,并且服務器也已對它進行確認,除非客戶端是在實行半關閉狀態(tài),否則將等待服務器主機的應用層處理關閉連接,因為服務器已經意識到它已收到FIN報文段,它需要發(fā)一個 FIN 來關閉<服務器 -> 客戶端>方向上的連接。這樣客戶端這端才會從FIN_WAIT_2狀態(tài)進入TIME_WAIT狀態(tài)。如果是網絡不好或者是服務器不發(fā)送FIN報文段的時候,這意味著客戶端這端可能永遠保持這個FIN_WAIT_2狀態(tài),從而無法 進入CLOSE_WAIT狀態(tài),并一直占用這個端口連接或者socket,在嵌入式中,如果存在多個這種狀態(tài)的話,則這很可能導致內存耗盡。CLOSE_WAIT:在收到客戶端主動斷開連接的 FIN 報文段(第一次揮手)后,服務器返回給客戶端確認報文段(第二次揮手)后的狀態(tài)。TIME_WAIT狀態(tài):TIME_WAIT狀態(tài)也稱為2MSL等待狀態(tài)。
具體見下圖:
-
.
紅色虛線:表示服務器的狀態(tài)轉移。 -
. 黑色實線:表示客戶端的狀態(tài)轉移。

TCP協議狀態(tài)轉移
RST報文
順便再提一點不太常見的TCP協議狀態(tài)轉移,主要是針對服務器端的(綠色那條):
- 服務器在收到
SYN握手報文后,再收到了客戶端的RST報文,那么它會重新進入監(jiān)聽狀態(tài),再重新等待連接。
一般說來,無論何時一個報文段發(fā)往基準的連接出現錯誤, TCP都會發(fā)出一個復位報文段(這里提到的基準的連接是指由目的 IP地址、目的端口號、源 IP地址和源端口號都是已知的連接。
此外產生復位的另一種常見情況是當連接請求到達時,目的端口并沒有在監(jiān)聽中,當一個數據報到達目的端口時,它將產生一個ICMP端口不可達的信息,同時TCP協議將進行復位,當然啦,在lwip中這些ICMP端口不可達報文都會被丟棄的,也不用管那么多。
TIME_WAIT狀態(tài)
第一次看這個轉移圖的時候,可能很多人都有疑惑,為什么要有一個 TIME_WAIT 狀態(tài)?為什么不能直接到達 CLOSED 狀態(tài)?
每個具體TCP連接的實現必須選擇一個TCP報文段最大生存時間MSL(Maximum Segment Lifetime),就如IP數據報中的TTL字段表示報文在網絡中生存的時間一樣。MSL是任何報文段被丟棄前在網絡內的最長時間,這個時間是有限的,為什么需要等待呢?我們知道 IP數據報 是不可靠的,而TCP報文段是封裝在IP數據報中,TCP協議必須保證發(fā)出的 ACK 報文段是正確被對方接收, 因此處于該狀態(tài)的主機必須在這個狀態(tài)停留最長時間為2倍的MSL,以防最后這個ACK丟失,因為TCP協議必須保證數據能準確送達目的地。
我們來假設一下 :假設沒有 TIME_WAIT 這種狀態(tài)。現實中,網絡環(huán)境不是理想的。在數據包傳輸的過程中,難免會有一些延時啊、丟包啊的情況發(fā)生。如果在客戶端的最后一個確認報文段發(fā)出去之后,由于某種原因,沒有到達服務端,服務端在超時后,就會向客戶端重新發(fā)一個 FIN 報文段,請求重傳這個已經丟失的確認報文段。但由于在客戶端,連接實際上已經斷開,端口已經關閉。那么在客戶端收到這個報文段后,會向服務端發(fā)送一個 RST 報文段請求重連(這也是為什么我要在前面講解RST的原因 ),而此時服務器收到這個 RST報文段后,會認為是錯誤的,因為在服務器看來都沒斷開連接,它所期望收到的是確認報文段。所以這個時候客戶端是不允許直接CLOSE關閉了事的,因此它需要等待服務器確認了,再CLOSE。
再假設一下:如果沒有 TIME_WAIT 這種狀態(tài),客戶端在關閉連接后,再次成功建立新的連接,客戶端任然可能會收到服務器的最后一個確認報文段,但是由于序號不同(重新建立連接時的序號是隨機的,這點很重要,要記?。?,客戶端會要求服務端重傳數據包,這樣,連接就必然會混亂出錯。而在 TIME_WAIT 這種狀態(tài)等待一段時間是為了讓本次連接的時間內所產生的所有報文都從網絡中消失,使得下一個新的連接不會出現舊的報文。
而 TIME_WAIT 狀態(tài)的等待時間一般是 2MAL ,并且客戶端連接的端口沒有釋放,這樣,讓前一個連接的報文段有足夠的時間被處理或者丟棄,也就不會出現這個問題。
這才是TCP協議優(yōu)雅且可靠的終止連接方式??!太強大了,我得膜拜一下~
-
狀態(tài)
+關注
關注
0文章
16瀏覽量
12131 -
LwIP
+關注
關注
2文章
89瀏覽量
29237 -
TCP協議
+關注
關注
1文章
101瀏覽量
12700
發(fā)布評論請先 登錄
TCP通訊狀態(tài)如何獲取
關于VISA端口狀態(tài)轉移方式
關于VISA狀態(tài)轉移問題
基于狀態(tài)轉移的獨立按鍵程序設計
狀態(tài)機下載到片子,狀態(tài)不轉移。
觸發(fā)器的狀態(tài)轉移圖和激勵表
線性系統狀態(tài)轉移矩陣討論
TCP IP協議有什么樣的狀態(tài)
一種可轉移的對話狀態(tài)生成器
汽車系統功能分析和狀態(tài)轉移圖資料下載
PLC單流程狀態(tài)轉移圖編程怎么操作
TCP狀態(tài)流轉圖詳解
TCP協議的連接狀態(tài)

什么是TCP狀態(tài)轉移
評論