TCP狀態(tài)轉(zhuǎn)移
在前一篇文章【面試必考】TCP協(xié)議“三次握手”與“四次揮手”已經(jīng)介紹了TCP
協(xié)議的三次握手和四次揮手。總的來說,TCP通信過程包括三個(gè)步驟:建立TCP連接(三次握手)、數(shù)據(jù)傳輸、終止TCP連接(四次揮手)。但是在這個(gè)通信過程中,有非常復(fù)雜的狀態(tài)問題,下面就來了解一下進(jìn)行TCP協(xié)議通信時(shí)候的狀態(tài)轉(zhuǎn)移。
TCP協(xié)議根據(jù)連接時(shí)接收到報(bào)文的不同類型,采取相應(yīng)動(dòng)作也不同,還要處理各個(gè)狀態(tài)的關(guān)系,如當(dāng)收到握手報(bào)文時(shí)候、超時(shí)的時(shí)候、用戶主動(dòng)關(guān)閉的時(shí)候等都需要不一樣的狀態(tài)去采取不一樣的處理。在LwIP中,為了實(shí)現(xiàn)TCP
協(xié)議的狀態(tài)描述,定義了11種連接時(shí)候的狀態(tài):
1static const char *const tcp_state_str[] = {
2 "CLOSED", //關(guān)閉狀態(tài)(無(wú)連接)
3 "LISTEN", //監(jiān)聽狀態(tài)
4 "SYN_SENT", //已發(fā)起請(qǐng)求連接(等待確認(rèn))
5 "SYN_RCVD", //已收到請(qǐng)求連接
6 "ESTABLISHED",//穩(wěn)定連接狀態(tài)
7 "FIN_WAIT_1", //單向請(qǐng)求終止連接狀態(tài)
8 "FIN_WAIT_2", //對(duì)方已應(yīng)答請(qǐng)求終止連接
9 "CLOSE_WAIT", //等待終止連接
10 "CLOSING", //兩端同時(shí)關(guān)閉
11 "LAST_ACK", //服務(wù)器等待對(duì)方接受關(guān)閉
12 "TIME_WAIT" //關(guān)閉成功(2MSL等待狀態(tài))
13};
LISTEN
:表示監(jiān)聽狀態(tài)。服務(wù)器
調(diào)用了listen函數(shù)進(jìn)入監(jiān)聽狀態(tài),客戶端可以開始進(jìn)行連接了。SYN_SENT
:表示客戶端已經(jīng)發(fā)送了SYN
報(bào)文請(qǐng)求連接(同時(shí)在等待服務(wù)器的確認(rèn))。當(dāng)客戶端調(diào)用connect
函數(shù)發(fā)起連接時(shí),首先發(fā)SYN給服務(wù)端,然后自己進(jìn)入SYN_SENT
狀態(tài),并等待服務(wù)端發(fā)送ACK+SYN
報(bào)文(握手應(yīng)答報(bào)文)進(jìn)行確認(rèn)。SYN_RCVD
:在每一個(gè) TCP 連接建立時(shí),都要進(jìn)行三次握手,這個(gè)狀態(tài)表示服務(wù)器
接收到客戶端發(fā)來的同步報(bào)文段(第一次握手),并且向客戶端發(fā)送了確認(rèn)同步報(bào)文段(第二次握手)之后的狀態(tài),在這個(gè)狀態(tài)時(shí),其實(shí)連接已經(jīng)經(jīng)歷了兩次握手。ESTABLISHED
:這個(gè)狀態(tài)是處于穩(wěn)定連接狀態(tài),建立連接的TCP協(xié)議兩端的主機(jī)都是處于這個(gè)狀態(tài),它們相互知道彼此的窗口大小、序列號(hào)、最大報(bào)文段等信息。FIN_WAIT_1
與FIN_WAIT_2
:處于這個(gè)狀態(tài)一般都是客戶端主機(jī)
單向請(qǐng)求終止連接,然后主機(jī)等待服務(wù)器
的回應(yīng),而如果服務(wù)器產(chǎn)生應(yīng)答,則主機(jī)狀態(tài)轉(zhuǎn)移為FIN_WAIT_2
,此時(shí)<客戶端 -> 服務(wù)器
>方向上的TCP連接就斷開,但是<服務(wù)器 -> 客戶端
>方向上的連接還是存在的。此處有一個(gè)注意的地方:如果主機(jī)處于FIN_WAIT_2
狀態(tài),說明主機(jī)已經(jīng)發(fā)出了FIN
報(bào)文段,并且服務(wù)器也已對(duì)它進(jìn)行確認(rèn),除非客戶端是在實(shí)行半關(guān)閉狀態(tài),否則將等待服務(wù)器主機(jī)的應(yīng)用層處理關(guān)閉連接,因?yàn)榉?wù)器已經(jīng)意識(shí)到它已收到FIN
報(bào)文段,它需要發(fā)一個(gè) FIN 來關(guān)閉<服務(wù)器 -> 客戶端
>方向上的連接。這樣客戶端這端才會(huì)從FIN_WAIT_2
狀態(tài)進(jìn)入TIME_WAIT
狀態(tài)。如果是網(wǎng)絡(luò)不好或者是服務(wù)器不發(fā)送FIN
報(bào)文段的時(shí)候,這意味著客戶端這端可能永遠(yuǎn)保持這個(gè)FIN_WAIT_2
狀態(tài),從而無(wú)法 進(jìn)入CLOSE_WAIT
狀態(tài),并一直占用這個(gè)端口連接或者socket
,在嵌入式中,如果存在多個(gè)這種狀態(tài)的話,則這很可能導(dǎo)致內(nèi)存耗盡。CLOSE_WAIT
:在收到客戶端
主動(dòng)斷開連接的 FIN 報(bào)文段(第一次揮手)后,服務(wù)器
返回給客戶端確認(rèn)報(bào)文段(第二次揮手)后的狀態(tài)。TIME_WAIT
狀態(tài):TIME_WAIT
狀態(tài)也稱為2MSL等待狀態(tài)
。
具體見下圖:
-
.
紅色
虛線:表示服務(wù)器的狀態(tài)轉(zhuǎn)移。 -
. 黑色實(shí)線:表示客戶端的狀態(tài)轉(zhuǎn)移。
TCP協(xié)議狀態(tài)轉(zhuǎn)移
RST報(bào)文
順便再提一點(diǎn)不太常見的TCP協(xié)議狀態(tài)轉(zhuǎn)移,主要是針對(duì)服務(wù)器端的(綠色那條):
- 服務(wù)器在收到
SYN
握手報(bào)文后,再收到了客戶端的RST
報(bào)文,那么它會(huì)重新進(jìn)入監(jiān)聽狀態(tài),再重新等待連接。
一般說來,無(wú)論何時(shí)一個(gè)報(bào)文段發(fā)往基準(zhǔn)的連接出現(xiàn)錯(cuò)誤, TCP
都會(huì)發(fā)出一個(gè)復(fù)位報(bào)文段(這里提到的基準(zhǔn)的連接
是指由目的 IP地址、目的端口號(hào)、源 IP地址和源端口號(hào)都是已知
的連接。
此外產(chǎn)生復(fù)位的另一種常見情況是當(dāng)連接請(qǐng)求到達(dá)時(shí),目的端口并沒有在監(jiān)聽中,當(dāng)一個(gè)數(shù)據(jù)報(bào)到達(dá)目的端口時(shí),它將產(chǎn)生一個(gè)ICMP
端口不可達(dá)的信息,同時(shí)TCP協(xié)議將進(jìn)行復(fù)位,當(dāng)然啦,在lwip中這些ICMP
端口不可達(dá)報(bào)文都會(huì)被丟棄的,也不用管那么多。
TIME_WAIT狀態(tài)
第一次看這個(gè)轉(zhuǎn)移圖的時(shí)候,可能很多人都有疑惑,為什么要有一個(gè) TIME_WAIT
狀態(tài)?為什么不能直接到達(dá) CLOSED
狀態(tài)?
每個(gè)具體TCP
連接的實(shí)現(xiàn)必須選擇一個(gè)TCP
報(bào)文段最大生存時(shí)間MSL
(Maximum Segment Lifetime),就如IP數(shù)據(jù)報(bào)
中的TTL
字段表示報(bào)文在網(wǎng)絡(luò)中生存的時(shí)間一樣。MSL
是任何報(bào)文段被丟棄前在網(wǎng)絡(luò)內(nèi)的最長(zhǎng)時(shí)間,這個(gè)時(shí)間是有限的,為什么需要等待呢?我們知道 IP數(shù)據(jù)報(bào) 是不可靠的,而TCP報(bào)文段是封裝在IP數(shù)據(jù)報(bào)中,TCP協(xié)議必須保證發(fā)出的 ACK 報(bào)文段是正確被對(duì)方接收, 因此處于該狀態(tài)的主機(jī)必須在這個(gè)狀態(tài)停留最長(zhǎng)時(shí)間為2倍的MSL,以防最后這個(gè)ACK丟失,因?yàn)門CP協(xié)議必須保證數(shù)據(jù)能準(zhǔn)確送達(dá)目的地。
我們來假設(shè)一下 :假設(shè)沒有 TIME_WAIT
這種狀態(tài)。現(xiàn)實(shí)中,網(wǎng)絡(luò)環(huán)境不是理想的。在數(shù)據(jù)包傳輸?shù)倪^程中,難免會(huì)有一些延時(shí)啊、丟包啊
的情況發(fā)生。如果在客戶端的最后一個(gè)確認(rèn)報(bào)文段
發(fā)出去之后,由于某種原因,沒有到達(dá)服務(wù)端,服務(wù)端在超時(shí)后,就會(huì)向客戶端重新發(fā)一個(gè) FIN 報(bào)文段,請(qǐng)求重傳這個(gè)已經(jīng)丟失的確認(rèn)報(bào)文段
。但由于在客戶端,連接實(shí)際上已經(jīng)斷開,端口已經(jīng)關(guān)閉。那么在客戶端收到這個(gè)報(bào)文段后,會(huì)向服務(wù)端發(fā)送一個(gè) RST
報(bào)文段請(qǐng)求重連(這也是為什么我要在前面講解RST
的原因 ),而此時(shí)服務(wù)器收到這個(gè) RST
報(bào)文段后,會(huì)認(rèn)為是錯(cuò)誤的,因?yàn)樵诜?wù)器看來都沒斷開連接,它所期望收到的是確認(rèn)報(bào)文段。所以這個(gè)時(shí)候客戶端是不允許直接CLOSE
關(guān)閉了事的,因此它需要等待服務(wù)器確認(rèn)了,再CLOSE
。
再假設(shè)一下:如果沒有 TIME_WAIT
這種狀態(tài),客戶端在關(guān)閉連接后,再次成功建立新的連接
,客戶端任然可能會(huì)收到服務(wù)器的最后一個(gè)確認(rèn)報(bào)文段
,但是由于序號(hào)
不同(重新建立連接時(shí)的序號(hào)是隨機(jī)
的,這點(diǎn)很重要,要記住),客戶端會(huì)要求服務(wù)端重傳
數(shù)據(jù)包,這樣,連接就必然會(huì)混亂出錯(cuò)。而在 TIME_WAIT
這種狀態(tài)等待一段時(shí)間是為了讓本次連接的時(shí)間內(nèi)所產(chǎn)生的所有報(bào)文都從網(wǎng)絡(luò)中消失,使得下一個(gè)新的連接不會(huì)出現(xiàn)舊的報(bào)文。
而 TIME_WAIT
狀態(tài)的等待時(shí)間一般是 2MAL
,并且客戶端連接的端口沒有釋放,這樣,讓前一個(gè)連接的報(bào)文段有足夠的時(shí)間被處理或者丟棄,也就不會(huì)出現(xiàn)這個(gè)問題。
這才是TCP協(xié)議優(yōu)雅且可靠
的終止連接方式啊!太強(qiáng)大了,我得膜拜一下~
-
狀態(tài)
+關(guān)注
關(guān)注
0文章
16瀏覽量
12032 -
LwIP
+關(guān)注
關(guān)注
2文章
89瀏覽量
28135 -
TCP協(xié)議
+關(guān)注
關(guān)注
1文章
101瀏覽量
12391
發(fā)布評(píng)論請(qǐng)先 登錄
狀態(tài)轉(zhuǎn)移圖的研究及單流程編程訓(xùn)練實(shí)驗(yàn)

TCP通訊狀態(tài)如何獲取
關(guān)于VISA端口狀態(tài)轉(zhuǎn)移方式
關(guān)于VISA狀態(tài)轉(zhuǎn)移問題
基于狀態(tài)轉(zhuǎn)移的獨(dú)立按鍵程序設(shè)計(jì)
狀態(tài)機(jī)下載到片子,狀態(tài)不轉(zhuǎn)移。
觸發(fā)器的狀態(tài)轉(zhuǎn)移圖和激勵(lì)表

線性系統(tǒng)狀態(tài)轉(zhuǎn)移矩陣討論
TCP IP協(xié)議有什么樣的狀態(tài)
一種可轉(zhuǎn)移的對(duì)話狀態(tài)生成器
汽車系統(tǒng)功能分析和狀態(tài)轉(zhuǎn)移圖資料下載

PLC單流程狀態(tài)轉(zhuǎn)移圖編程怎么操作
TCP狀態(tài)機(jī)設(shè)計(jì)與實(shí)現(xiàn)

TCP狀態(tài)流轉(zhuǎn)圖詳解

TCP協(xié)議的連接狀態(tài)

評(píng)論