基礎(chǔ)教程:TCP連接的建立和釋放
TCP首部格式
先看TCP報(bào)文段的格式,如下;
TCP報(bào)文段首部的前20個(gè)字節(jié)是固定的,后面有4N字節(jié)是根據(jù)需要而增加的選項(xiàng)。因此TCP報(bào)文段的最小長(zhǎng)度為20個(gè)字節(jié)。
首部固定部分的各字段的意義如下:
1、源端口和目的端口:加上IP首部的源IP地址和目的IP地址,確定唯一的一個(gè)TCP連接。另外通過(guò)目的端口來(lái)決定TCP將數(shù)據(jù)報(bào)交付于那個(gè)應(yīng)用程序,從而實(shí)現(xiàn)TCP的分用功能。
2、序號(hào):占4個(gè)字節(jié),序號(hào)的范圍為[0,4284967296]。由于TCP是面向字節(jié)流的,在一個(gè)TCP連接中傳送的字節(jié)流中的每一個(gè)字節(jié)都按順序編號(hào),首部中的序號(hào)字段則是指本報(bào)文段所發(fā)送的數(shù)據(jù)的***個(gè)字節(jié)的序號(hào)。另外,序號(hào)是循環(huán)使用的,當(dāng)序號(hào)增加到***值時(shí),下一個(gè)序號(hào)就又回到了0。
3、確認(rèn)號(hào):當(dāng)ACK標(biāo)志位為1時(shí)有效,表示期望收到的下一個(gè)報(bào)文段的***個(gè)數(shù)據(jù)字節(jié)的序號(hào)。確認(rèn)號(hào)為N,則表明到序號(hào)N-1為止的所有數(shù)據(jù)字節(jié)都已經(jīng)被正確地接收到了。
4、頭部長(zhǎng)度:TCP報(bào)文段的頭部長(zhǎng)度,它指出TCP報(bào)文段的數(shù)據(jù)部分的起始位置與TCP報(bào)文段的起始位置的距離。頭部長(zhǎng)度占4個(gè)字節(jié),但它的單位是32位字,即以4字節(jié)為計(jì)算單位,因此頭部長(zhǎng)度的***值為15*4=60個(gè)字節(jié),這就意味著選項(xiàng)的長(zhǎng)度不超過(guò)40個(gè)字節(jié)。
5、保留位:必須為0.
6、下面的六個(gè)控制位說(shuō)明報(bào)文段的性質(zhì):
1)URG:與首部中的緊急指針字段配合使用。URG為1時(shí),表明緊急指針字段有效,發(fā)送應(yīng)用進(jìn)程告訴發(fā)送方的TCP有緊急數(shù)據(jù)要傳送,于是發(fā)送方TCP就把緊急數(shù)據(jù)插入到本報(bào)文段數(shù)據(jù)的最前面,而其后面仍是普通數(shù)據(jù)。
2)ACK:僅當(dāng)ACK=1時(shí)確認(rèn)號(hào)字段才有效,當(dāng)ACK=0時(shí),確認(rèn)號(hào)無(wú)效。TCP規(guī)定,在連接建立后所有的傳送報(bào)文段都必須把ACK置1。
3)PSH:如果發(fā)送的報(bào)文段中PSH為1,則接收方接受到該報(bào)文段后,直接將其交付給應(yīng)用進(jìn)程,而不再等待整個(gè)緩存都填滿后再向上交付。
4)RST:復(fù)位標(biāo)志,RST=1時(shí),表明TCP連接中出現(xiàn)嚴(yán)重差錯(cuò),必須釋放連接,然后重新建立運(yùn)輸連接。
5)SYN:同步序號(hào),用來(lái)發(fā)起一個(gè)連接。當(dāng)SYN=1而ACK=0時(shí),表明這是一個(gè)連接請(qǐng)求報(bào)文段,若對(duì)方同意建立連接,則應(yīng)在響應(yīng)的報(bào)文段中使SYN=1和ACK=1。
6)FIN:用來(lái)釋放一個(gè)連接。當(dāng)FIN=1時(shí),表明此報(bào)文段的發(fā)送方的數(shù)據(jù)已發(fā)送完畢,并要求釋放連接。
7、窗口:接收方讓發(fā)送方下次發(fā)送報(bào)文段時(shí)設(shè)置的發(fā)送窗口的大小。
8、校驗(yàn)和:校驗(yàn)的字段范圍包括首部和數(shù)據(jù)這兩部分。
9、緊急指針:緊急指針當(dāng)URG=1時(shí)才有效,它指出本報(bào)文段中的緊急數(shù)據(jù)的字節(jié)數(shù)。值得注意的是,即使窗口為0時(shí),也可發(fā)送緊急數(shù)據(jù)。
10、選項(xiàng)與填充:選項(xiàng)應(yīng)該為4字節(jié)的整數(shù)倍,否則用0填充。最常見(jiàn)的可選字段是最長(zhǎng)報(bào)文大小MSS(Maximum Segment Size),每個(gè)連接方通常都在通信的***個(gè)報(bào)文段中指明這個(gè)選項(xiàng)。它指明本端所能接收的***長(zhǎng)度的報(bào)文段。該選項(xiàng)如果不設(shè)置,默認(rèn)為536(20+20+536=576字節(jié)的IP數(shù)據(jù)報(bào)),其中ip首部和tcp首部各20個(gè)字節(jié),而internet 上標(biāo)準(zhǔn)的MTU (最小)為576B。#p#
TCP連接的建立
下圖為TCP三次握手連接的建立過(guò)程:
服務(wù)端的TCP進(jìn)程先創(chuàng)建傳輸控制塊TCB,準(zhǔn)備接受客戶端進(jìn)程的連接請(qǐng)求,然后服務(wù)端進(jìn)程處于LISTEN狀態(tài),等待客戶端的連接請(qǐng)求,如有,則作出響應(yīng)。
1、客戶端的TCP進(jìn)程也首先創(chuàng)建傳輸控制模塊TCB,然后向服務(wù)端發(fā)出連接請(qǐng)求報(bào)文段,該報(bào)文段首部中的SYN=1,ACK=0,同時(shí)選擇一個(gè)初始序號(hào)seq=i。TCP規(guī)定,SYN=1的報(bào)文段不能攜帶數(shù)據(jù),但要消耗掉一個(gè)序號(hào)。這時(shí),TCP客戶進(jìn)程進(jìn)入SYN—SENT(同步已發(fā)送)狀態(tài),這是TCP連接的***次握手。
2、服務(wù)端收到客戶端發(fā)來(lái)的請(qǐng)求報(bào)文后,如果同意建立連接,則向客戶端發(fā)送確認(rèn)。確認(rèn)報(bào)文中的SYN=1,ACK=1,確認(rèn)號(hào)ack=i+1,同時(shí)為自己選擇一個(gè)初始序號(hào)seq=j。同樣該報(bào)文段也是SYN=1的報(bào)文段,不能攜帶數(shù)據(jù),但同樣要消耗掉一個(gè)序號(hào)。這時(shí),TCP服務(wù)端進(jìn)入SYN—RCVD(同步收到)狀態(tài),這是TCP連接的第二次握手。
3、TCP客戶端進(jìn)程收到服務(wù)端進(jìn)程的確認(rèn)后,還要向服務(wù)端給出確認(rèn)。確認(rèn)報(bào)文段的ACK=1,確認(rèn)號(hào)ack=j+1,而自己的序號(hào)為seq=i+1。TCP的標(biāo)準(zhǔn)規(guī)定,ACK報(bào)文段可以攜帶數(shù)據(jù),但如果不攜帶數(shù)據(jù)則不消耗序號(hào),因此,如果不攜帶數(shù)據(jù),則下一個(gè)報(bào)文段的序號(hào)仍為seq=i+1。這時(shí),TCP連接已經(jīng)建立,客戶端進(jìn)入ESTABLISHED(已建立連接)狀態(tài)。這是TCP連接的第三次握手,可以看出第三次握手客戶端已經(jīng)可以發(fā)送攜帶數(shù)據(jù)的報(bào)文段了。
當(dāng)服務(wù)端收到確認(rèn)后,也進(jìn)入ESTABLISHED(已建立連接)狀態(tài)。
雙方同時(shí)主動(dòng)連接的TCP連接建立過(guò)程
正常情況下,傳輸連接都是由一方主動(dòng)發(fā)起的,但也有可能雙方同時(shí)主動(dòng)發(fā)起連接,此時(shí)就會(huì)發(fā)生連接碰撞,最終只有一個(gè)連接能夠建立起來(lái)。因?yàn)樗羞B接都是由它們的端點(diǎn)進(jìn)行標(biāo)識(shí)的。如果***個(gè)連接請(qǐng)求建立起一個(gè)由套接字(x,y)標(biāo)識(shí)的連接,而第二個(gè)連接也建立了這樣一個(gè)連接,那么在TCP實(shí)體內(nèi)部只有一個(gè)套接字表項(xiàng)。
當(dāng)出現(xiàn)同時(shí)發(fā)出連接請(qǐng)求時(shí),則兩端幾乎在同時(shí)發(fā)送一個(gè)SYN字段置1的數(shù)據(jù)段,并進(jìn)入SYN_SENT狀態(tài)。當(dāng)每一端收到SYN數(shù)據(jù)段時(shí),狀態(tài)變?yōu)镾YN_RCVD,同時(shí)它們都再發(fā)送SYN字段置1,ACK字段置1的數(shù)據(jù)段,對(duì)收到的SYN數(shù)據(jù)段進(jìn)行確認(rèn)。當(dāng)雙方都收到對(duì)方的SYN+ACK數(shù)據(jù)段后,便都進(jìn)入ESTABLISHED狀態(tài)。圖10-39顯示了這種同時(shí)發(fā)起連接的連接過(guò)程,但最終建立的是一個(gè)TCP連接,而不是兩個(gè),這點(diǎn)要特別注意。
從圖中可以看出,一個(gè)雙方同時(shí)打開的傳輸連接需要交換4數(shù)據(jù)段,比正常的傳輸連接建立所進(jìn)行的三次握手多交換一個(gè)數(shù)據(jù)段。此外要注意的是,此時(shí)我們沒(méi)有將任何一端稱為客戶或服務(wù)器,因?yàn)槊恳欢思仁强蛻粲质欠?wù)器。
為什么一定要進(jìn)行三次握手呢?
前兩次的握手很顯然是必須的,主要是***一次,即客戶端收到服務(wù)端發(fā)來(lái)的確認(rèn)后為什么還要想服務(wù)端再發(fā)送一次確認(rèn)呢?這主要是為了防止已失效的請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端而產(chǎn)生連接的誤判。
考慮如下的情況:客戶端發(fā)送了一個(gè)連接請(qǐng)求報(bào)文段到服務(wù)端,但是在某些網(wǎng)絡(luò)節(jié)點(diǎn)上長(zhǎng)時(shí)間滯留了,而后客戶端又超時(shí)重發(fā)了一個(gè)連接請(qǐng)求報(bào)文段該服務(wù)端,而后正常建立連接,數(shù)據(jù)傳輸完畢,并釋放了連接。如果這時(shí)候***次發(fā)送的請(qǐng)求報(bào)文段延遲了一段時(shí)間后,又到了服務(wù)端,很顯然,這本是一個(gè)早已失效的報(bào)文段,但是服務(wù)端收到后會(huì)誤以為客戶端又發(fā)出了一次連接請(qǐng)求,于是向客戶端發(fā)出確認(rèn)報(bào)文段,并同意建立連接。假設(shè)不采用三次握手,這時(shí)服務(wù)端只要發(fā)送了確認(rèn),新的連接就建立了,但由于客戶端比你更沒(méi)有發(fā)出建立連接的請(qǐng)求,因此不會(huì)理會(huì)服務(wù)端的確認(rèn),也不會(huì)向服務(wù)端發(fā)送數(shù)據(jù),而服務(wù)端卻認(rèn)為新的連接已經(jīng)建立了,并在一直等待客戶端發(fā)送數(shù)據(jù),這樣服務(wù)端就會(huì)一直等待下去,直到超出保活計(jì)數(shù)器的設(shè)定值,而將客戶端判定為出了問(wèn)題,才會(huì)關(guān)閉這個(gè)連接。這樣就浪費(fèi)了很多服務(wù)器的資源。而如果采用三次握手,客戶端就不會(huì)向服務(wù)端發(fā)出確認(rèn),服務(wù)端由于收不到確認(rèn),就知道客戶端沒(méi)有要求建立連接,從而不建立該連接。#p#
TCP連接的釋放
下圖為TCP四次揮手的釋放過(guò)程:
數(shù)據(jù)傳輸結(jié)束后,通信的雙方都可以釋放連接,并停止發(fā)送數(shù)據(jù)。假設(shè)現(xiàn)在客戶端和服務(wù)端都處于ESTABLISHED狀態(tài)。
1、客戶端A的TCP進(jìn)程先向服務(wù)端發(fā)出連接釋放報(bào)文段,并停止發(fā)送數(shù)據(jù),主動(dòng)關(guān)閉TCP連接。釋放連接報(bào)文段中FIN=1,序號(hào)為seq=u,該序號(hào)等于前面已經(jīng)傳送過(guò)去的數(shù)據(jù)的***一個(gè)字節(jié)的序號(hào)加1。這時(shí),A進(jìn)入FIN—WAIT-1(終止等待1)狀態(tài),等待B的確認(rèn)。TCP規(guī)定,F(xiàn)IN報(bào)文段即使不攜帶數(shù)據(jù),也要消耗掉一個(gè)序號(hào)。這是TCP連接釋放的***次揮手。
2、B收到連接釋放報(bào)文段后即發(fā)出確認(rèn)釋放連接的報(bào)文段,該報(bào)文段中,ACK=1,確認(rèn)號(hào)為ack=u+1,其自己的序號(hào)為v,該序號(hào)等于B前面已經(jīng)傳送過(guò)的數(shù)據(jù)的***一個(gè)字節(jié)的序號(hào)加1。然后B進(jìn)入CLOSE—WAIT(關(guān)閉等待)狀態(tài),此時(shí)TCP服務(wù)器進(jìn)程應(yīng)該通知上層的應(yīng)用進(jìn)程,因而A到B這個(gè)方向的連接就釋放了,這時(shí)TCP處于半關(guān)閉狀態(tài),即A已經(jīng)沒(méi)有數(shù)據(jù)要發(fā)了,但B若發(fā)送數(shù)據(jù),A仍要接受,也就是說(shuō)從B到A這個(gè)方向的連接并沒(méi)有關(guān)閉,這個(gè)狀態(tài)可能會(huì)持續(xù)一些時(shí)間。這是TCP連接釋放的第二次揮手。
3、A收到B的確認(rèn)后,就進(jìn)入了FIN—WAIT(終止等待2)狀態(tài),等待B發(fā)出連接釋放報(bào)文段,如果B已經(jīng)沒(méi)有要向A發(fā)送的數(shù)據(jù)了,其應(yīng)用進(jìn)程就通知TCP釋放連接。這時(shí)B發(fā)出的鏈接釋放報(bào)文段中,F(xiàn)IN=1,確認(rèn)號(hào)還必須重復(fù)上次已發(fā)送過(guò)的確認(rèn)號(hào),即ack=u+1,序號(hào)seq=w,因?yàn)樵诎腙P(guān)閉狀態(tài)B可能又發(fā)送了一些數(shù)據(jù),因此該序號(hào)為半關(guān)閉狀態(tài)發(fā)送的數(shù)據(jù)的***一個(gè)字節(jié)的序號(hào)加1。這時(shí)B進(jìn)入LAST—ACK(***確認(rèn))狀態(tài),等待A的確認(rèn),這是TCP連接的第三次揮手。
4、A收到B的連接釋放請(qǐng)求后,必須對(duì)此發(fā)出確認(rèn)。確認(rèn)報(bào)文段中,ACK=1,確認(rèn)號(hào)ack=w+1,而自己的序號(hào)seq=u+1,而后進(jìn)入TIME—WAIT(時(shí)間等待)狀態(tài)。這時(shí)候,TCP連接還沒(méi)有釋放掉,必須經(jīng)過(guò)時(shí)間等待計(jì)時(shí)器設(shè)置的時(shí)間2MSL后,A才進(jìn)入CLOSED狀態(tài),時(shí)間MSL叫做最長(zhǎng)報(bào)文壽命,RFC建議設(shè)為2分鐘,因此從A進(jìn)入TIME—WAIT狀態(tài)后,要經(jīng)過(guò)4分鐘才能進(jìn)入到CLOSED狀態(tài),而B只要收到了A的確認(rèn)后,就進(jìn)入了CLOSED狀態(tài)。二者都進(jìn)入CLOSED狀態(tài)后,連接就完全釋放了,這是TCP連接的第四次揮手。
雙方主動(dòng)關(guān)閉的TCP連接釋放流程
與可以雙方同時(shí)建立TCP傳輸連接一樣,TCP傳輸連接關(guān)閉也可以由雙方同時(shí)主動(dòng)進(jìn)行(正常情況下都是由一方發(fā)送***個(gè)FIN數(shù)據(jù)段進(jìn)行主動(dòng)連接關(guān)閉,另一方被動(dòng)接受連接關(guān)閉)
當(dāng)兩端對(duì)應(yīng)的網(wǎng)絡(luò)應(yīng)用層進(jìn)程同時(shí)調(diào)用CLOSE原語(yǔ),發(fā)送FIN數(shù)據(jù)段執(zhí)行關(guān)閉命令時(shí),兩端均從ESTABLISHED狀態(tài)轉(zhuǎn)變?yōu)镕IN WAIT 1狀態(tài)。任意一方收到對(duì)端發(fā)來(lái)的FIN數(shù)據(jù)段后,其狀態(tài)均由FIN WAIT 1轉(zhuǎn)變到CLOSING狀態(tài),并發(fā)送***的ACK數(shù)據(jù)段。當(dāng)收到***的ACK數(shù)據(jù)段后,狀態(tài)轉(zhuǎn)變化TIME_WAIT,在等待2MSL后進(jìn)入到CLOSED狀態(tài),最終釋放整個(gè)TCP傳輸連接。
為什么A在TIME—WAIT狀態(tài)必須等待2MSL時(shí)間呢?
1、為了保證A發(fā)送的***一個(gè)ACK報(bào)文段能夠到達(dá)B。該ACK報(bào)文段很有可能丟失,因而使處于在LIST—ACK狀態(tài)的B收不到對(duì)已發(fā)送的FIN+ACK報(bào)文段的確認(rèn),B可能會(huì)重傳這個(gè)FIN+ACK報(bào)文段,而A就在這2MSL時(shí)間內(nèi)收到這個(gè)重傳的FIN+ACK報(bào)文段,接著A重傳一次確認(rèn),重新啟動(dòng)2MSL計(jì)時(shí)器,***A和B都進(jìn)入CLOSED狀態(tài)。如果A在TIME—WAIT狀態(tài)不等待一段時(shí)間就直接釋放連接,到CLOSED狀態(tài),那么久無(wú)法收到B重傳的FIN+ACK報(bào)文段,也就不會(huì)再發(fā)送一次確認(rèn)ACK報(bào)文段,B就無(wú)法正常進(jìn)入CLOSED狀態(tài)。
2、防止已失效的請(qǐng)求連接出現(xiàn)在本連接中。在連接處于2MSL等待時(shí),任何遲到的報(bào)文段將被丟棄,因?yàn)樘幱?MSL等待的、由該插口(插口是IP和端口對(duì)的意思,socket)定義的連接在這段時(shí)間內(nèi)將不能被再用,這樣就可以使下一個(gè)新的連接中不會(huì)出現(xiàn)這種舊的連接之前延遲的報(bào)文段。
補(bǔ)充:
當(dāng)客戶端執(zhí)行主動(dòng)關(guān)閉并進(jìn)入TIME—WAIT是正常的,服務(wù)端執(zhí)行被動(dòng)關(guān)閉,不會(huì)進(jìn)入TIME—WAIT狀態(tài),這說(shuō)明,如果終止了一個(gè)客戶程序,并立即重啟該客戶程序,則新的客戶程序?qū)⒉辉僦赜孟嗤谋镜囟丝冢鞘褂眯碌亩丝冢@不會(huì)帶來(lái)什么問(wèn)題,因?yàn)榭蛻舳耸褂帽镜囟丝冢⒉魂P(guān)心這個(gè)端口是多少。但對(duì)于服務(wù)器來(lái)說(shuō),情況就不同了,服務(wù)器總是用我們熟知的端口,那么在2MSL時(shí)間內(nèi),重啟服務(wù)器就會(huì)出錯(cuò),為了避免這個(gè)錯(cuò)誤,服務(wù)器給出了一個(gè)平靜時(shí)間的概念,這是說(shuō)在2MSL時(shí)間內(nèi),雖然可以重新啟動(dòng)服務(wù)器,但是這個(gè)服務(wù)器還是要平靜的等待2MSL時(shí)間的過(guò)去才能進(jìn)行下一次連接。