- TCP協(xié)議介紹
TCP(Transmission Control Protocol),是一個面向連接的協(xié)議,在運(yùn)用次協(xié)議進(jìn)行傳輸數(shù)據(jù)之前,都會進(jìn)行三次握手的連接工作,當(dāng)數(shù)據(jù)傳輸完畢
,雙方都會通知對方要釋放此連接(四次揮手)。 -
TCP標(biāo)志位
SYN表示建立連接,F(xiàn)IN表示關(guān)閉連接,ACK表示響應(yīng),PSH表示有 DATA數(shù)據(jù)傳輸,RST表示連接重置。其中,ACK是可能與SYN,F(xiàn)IN等同時使用的,比如SYN和ACK可能同時為1,它表示的就是建立連接之后的響應(yīng),如果只是單個的一個SYN,它表示的只是建立連接。TCP的幾次握手就是通過這樣的ACK表現(xiàn)出來的。但SYN與FIN是不會同時為1的,因?yàn)榍罢弑硎镜氖墙⑦B接,而后者表示的是斷開連接。RST一般是在FIN之后才會出現(xiàn)為1的情況,表示的是連接重置。一般地,當(dāng)出現(xiàn)FIN包或RST包時,我們便認(rèn)為客戶端與服務(wù)器端斷開了連接;而當(dāng)出現(xiàn)SYN和SYN+ACK包時,我們認(rèn)為客戶端與服務(wù)器建立了一個連接。PSH為1的情況,一般只出現(xiàn)在 DATA內(nèi)容不為0的包中,也就是說PSH為1表示的是有真正的TCP數(shù)據(jù)包內(nèi)容被傳遞。TCP的連接建立和連接關(guān)閉,都是通過請求-響應(yīng)的模式完成的。 - 三次握手和四次揮手的圖解

Untitled 1.jpg
-
三次握手過程
主機(jī)A(client)和主機(jī)B(server)開始建立握手過程:
第一次握手:主機(jī)A發(fā)送位碼為syn=1,隨機(jī)產(chǎn)生seq number=10001的數(shù)據(jù)包到服務(wù)器,主機(jī)B由SYN=1知道,A要求建立聯(lián)機(jī),此時狀態(tài)為SYN_SENT;
第二次握手:主機(jī)B收到請求后要確認(rèn)聯(lián)機(jī)信息,向A發(fā)送ack number=(主機(jī)A的seq+1),syn=1,ack=1,隨機(jī)產(chǎn)生seq=20001的包,此時狀態(tài)由LISTEN變?yōu)镾YN_RECV;
第三次握手:主機(jī)A收到后檢查ack number是否正確,即第一次發(fā)送的seq number+1,以及位碼ack是否為1,若正確,主機(jī)A會再發(fā)送ack number=(主機(jī)B的seq+1),ack=1,主機(jī)B收到后確認(rèn)seq值與ack=1則連接建立成功,雙方狀態(tài)ESTABLISHED。
完成三次握手,主機(jī)A與主機(jī)B開始傳送數(shù)據(jù)。
各狀態(tài)含義解釋
CLOSED: 這個沒什么好說的了,表示初始狀態(tài)。
LISTEN: 這個也是非常容易理解的一個狀態(tài),表示服務(wù)器端的某個SOCKET處于監(jiān)聽狀態(tài),可以接受連接了。
SYN_RECV: 這個狀態(tài)表示接受到了SYN報(bào)文,在正常情況下,這個狀態(tài)是服務(wù)器端的SOCKET在建立TCP連接時的三次握手會話過程中的一個中間狀態(tài),很短暫,基本上用netstat你是很難看到這種狀態(tài)的,除非你特意寫了一個客戶端測試程序,故意將三次TCP握手過程中最后一個ACK報(bào)文不予發(fā)送。因此這種狀態(tài) 時,當(dāng)收到客戶端的ACK報(bào)文后,它會進(jìn)入到ESTABLISHED狀態(tài)。
SYN_SENT: 這個狀態(tài)與SYN_RECV遙相呼應(yīng),當(dāng)客戶端SOCKET執(zhí)行CONNECT連接時,它首先發(fā)送SYN報(bào)文,因此也隨即它會進(jìn)入到了SYN_SENT狀 態(tài),并等待服務(wù)端的發(fā)送三次握手中的第2個報(bào)文。SYN_SENT狀態(tài)表示客戶端已發(fā)送SYN報(bào)文。
ESTABLISHED:這個容易理解了,表示連接已經(jīng)建立了。 -
四次揮手各狀態(tài)解釋
TCP的連接的拆除需要發(fā)送四個包,因此稱為四次揮手(four-way handshake)。客戶端或服務(wù)器均可主動發(fā)起揮手動作。解析各種狀態(tài)含義:
FIN_WAIT_1: 這個狀態(tài)要好好解釋一下,其實(shí)FIN_WAIT_1和FIN_WAIT_2狀態(tài)的真正含義都是表示等待對方的FIN報(bào)文。而這兩種狀態(tài)的區(qū)別 是:FIN_WAIT_1狀態(tài)實(shí)際上是當(dāng)SOCKET在ESTABLISHED狀態(tài)時,它想主動關(guān)閉連接,向?qū)Ψ桨l(fā)送了FIN報(bào)文,此時該SOCKET即 進(jìn)入到FIN_WAIT_1狀態(tài)。而當(dāng)對方回應(yīng)ACK報(bào)文后,則進(jìn)入到FIN_WAIT_2狀態(tài),當(dāng)然在實(shí)際的正常情況下,無論對方何種情況下,都應(yīng)該馬上回應(yīng)ACK報(bào)文,所以FIN_WAIT_1狀態(tài)一般是比較難見到的,而FIN_WAIT_2狀態(tài)還有時常??梢杂胣etstat看到。
FIN_WAIT_2:上面已經(jīng)詳細(xì)解釋了這種狀態(tài),實(shí)際上FIN_WAIT_2狀態(tài)下的SOCKET,表示半連接,也即有一方要求close連接,但另外還告訴對方,我暫時還有點(diǎn)數(shù)據(jù)需要傳送給你,稍后再關(guān)閉接。
TIME_WAIT: 表示收到了對方的FIN報(bào)文,并發(fā)送出了ACK報(bào)文,就等2MSL后即可回到CLOSED可用狀態(tài)了。如果FIN_WAIT_1狀態(tài)下,收到了對方同時帶 FIN標(biāo)志和ACK標(biāo)志的報(bào)文時,可以直接進(jìn)入TIME_WAIT狀態(tài),而無須經(jīng)過FIN_WAIT_2狀態(tài)。
CLOSING: 這種狀態(tài)比較特殊,實(shí)際情況中應(yīng)該是很少見,屬于一種比較罕見的例外狀態(tài)。正常情況下,當(dāng)你發(fā)送FIN報(bào)文后,按理來說是應(yīng)該先收到(或同時收到)對方的 ACK報(bào)文,再收到對方的FIN報(bào)文。但是CLOSING狀態(tài)表示你發(fā)送FIN報(bào)文后,并沒有收到對方的ACK報(bào)文,反而卻也收到了對方的FIN報(bào)文。什 么情況下會出現(xiàn)此種情況呢?其實(shí)細(xì)想一下,也不難得出結(jié)論:那就是如果雙方幾乎在同時close一個SOCKET的話,那么就出現(xiàn)了雙方同時發(fā)送FIN報(bào) 文的情況,也即會出現(xiàn)CLOSING狀態(tài),表示雙方都正在關(guān)閉SOCKET連接。
CLOSE_WAIT: 這種狀態(tài)的含義其實(shí)是表示在等待關(guān)閉。怎么理解呢?當(dāng)對方close一個SOCKET后發(fā)送FIN報(bào)文給自己,你系統(tǒng)毫無疑問地會回應(yīng)一個ACK報(bào)文給對 方,此時則進(jìn)入到CLOSE_WAIT狀態(tài)。接下來呢,實(shí)際上你真正需要考慮的事情是看你是否還有數(shù)據(jù)發(fā)送給對方,如果沒有的話,那么你也就可以 close這個SOCKET,發(fā)送FIN報(bào)文給對方,也即關(guān)閉連接。所以你在CLOSE_WAIT狀態(tài)下,需要完成的事情是等待你去關(guān)閉連接。
LAST_ACK: 這個狀態(tài)還是比較容易好理解的,它是被動關(guān)閉一方在發(fā)送FIN報(bào)文后,最后等待對方的ACK報(bào)文。當(dāng)收到ACK報(bào)文后,也即可以進(jìn)入到CLOSED可用狀態(tài)了。 -
問題點(diǎn)
整理網(wǎng)上知識點(diǎn),有3個問題分析后得出的結(jié)論(不一定保證100%正確):
1、 為什么建立連接協(xié)議是三次握手,而關(guān)閉連接卻是四次握手呢?
這是因?yàn)榉?wù)端的LISTEN狀態(tài)下的SOCKET當(dāng)收到SYN報(bào)文的建連請求后,它可以把ACK和SYN(ACK起應(yīng)答作用,而SYN起同步作用)放在一 個報(bào)文里來發(fā)送。但關(guān)閉連接時,當(dāng)收到對方的FIN報(bào)文通知時,它僅僅表示對方?jīng)]有數(shù)據(jù)發(fā)送給你了;但未必你所有的數(shù)據(jù)都全部發(fā)送給對方了,所以你可以未 必會馬上會關(guān)閉SOCKET,也即你可能還需要發(fā)送一些數(shù)據(jù)給對方之后,再發(fā)送FIN報(bào)文給對方來表示你同意現(xiàn)在可以關(guān)閉連接了,所以它這里的ACK報(bào)文 和FIN報(bào)文多數(shù)情況下都是分開發(fā)送的。
2、 為什么TIME_WAIT狀態(tài)還需要等2MSL后才能返回到CLOSED狀態(tài)?
因?yàn)殡m然雙方都同意關(guān)閉連接了,而且握手的4個報(bào)文也都發(fā)送完畢,按理可以直接回到CLOSED 狀態(tài)(就好比從SYN_SENT 狀態(tài)到ESTABLISH 狀態(tài)那樣),但是我們必須假想網(wǎng)絡(luò)是不可靠的,你無法保證你(客戶端)最后發(fā)送的ACK報(bào)文一定會被對方收到,就是說對方處于LAST_ACK 狀態(tài)下的SOCKET可能會因?yàn)槌瑫r未收到ACK報(bào)文,而重發(fā)FIN報(bào)文,所以這個TIME_WAIT 狀態(tài)的作用就是用來重發(fā)可能丟失的ACK報(bào)文。
3、關(guān)閉TCP連接一定需要4次揮手嗎?
不一定,4次揮手關(guān)閉TCP連接是最安全的做法。但在有些時候,我們不喜歡TIME_WAIT 狀態(tài)(如當(dāng)MSL數(shù)值設(shè)置過大導(dǎo)致服務(wù)器端有太多TIME_WAIT狀態(tài)的TCP連接,減少這些條目數(shù)可以更快地關(guān)閉連接,為新連接釋放更多資源),這時我們可以通過設(shè)置SOCKET變量的SO_LINGER標(biāo)志來避免SOCKET在close()之后進(jìn)入TIME_WAIT狀態(tài),這時將通過發(fā)送RST強(qiáng)制終止TCP連接(取代正常的TCP四次握手的終止方式)。但這并不是一個很好的主意,TIME_WAIT 對于我們來說往往是有利的