詳解TCP協(xié)議,TCB,TCP的三次握手、四次揮手

TCP協(xié)議簡(jiǎn)介

TCP全稱Transmission Control Protocol,數(shù)據(jù)傳輸控制協(xié)議。它是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。

OSI:開(kāi)放式系統(tǒng)互聯(lián)模型

互聯(lián)網(wǎng)上的數(shù)據(jù)通過(guò)應(yīng)用層到物理層 層層封裝(添加頭部信息),由物理層傳輸?shù)綌?shù)據(jù)接收端,再層層解封裝,最后到到達(dá)數(shù)據(jù)接收端——應(yīng)用層。

常用的熟知端口號(hào)

應(yīng)用程序 FTP TFTP TELNET SMTP DNS HTTP SSH MYSQL
熟知端口 21,20 69 23 25 53 80 22 3306
傳輸層協(xié)議 TCP UDP TCP TCP UDP TCP TCP TCP

TCB是啥?

Socket包含兩部分,一個(gè)是IP地址,一個(gè)是端口號(hào)。同一個(gè)設(shè)備可以對(duì)應(yīng)一個(gè)IP地址,但不同的管道用不同的端口號(hào)區(qū)分,于是同一個(gè)設(shè)備發(fā)送給其他不同設(shè)備的信息就不會(huì)產(chǎn)生混亂。在同一時(shí)刻,設(shè)備可能會(huì)產(chǎn)生多種數(shù)據(jù)需要分發(fā)給不同的設(shè)備,為了確保數(shù)據(jù)能夠正確分發(fā),TCP協(xié)議用一種叫做TCB(Transmission Control Block,傳輸控制塊)的數(shù)據(jù)結(jié)構(gòu)把發(fā)給不同設(shè)備的數(shù)據(jù)封裝起來(lái)。

一個(gè)TCB數(shù)據(jù)塊包含了數(shù)據(jù)發(fā)送雙方對(duì)應(yīng)的socket信息以及擁有裝載數(shù)據(jù)的緩沖區(qū)。在兩個(gè)設(shè)備要建立連接發(fā)送數(shù)據(jù)之前,雙方都必須要做一些準(zhǔn)備工作,分配內(nèi)存建立起TCB數(shù)據(jù)塊就是連接建立前必須要做的準(zhǔn)備工作。我們還需要了解的一點(diǎn)是TCP連接的建立方式,由于TCP協(xié)議建立在服務(wù)器–客戶端的模式之上,因此對(duì)于兩種不同角色的設(shè)備,他們發(fā)起連接的方式不一樣。

客戶端發(fā)起連接的方式叫主動(dòng)打開(kāi)(Active Open)。也就是客戶端需要主動(dòng)向服務(wù)器發(fā)送消息,表達(dá)自己想建立數(shù)據(jù)連接的請(qǐng)求。服務(wù)器發(fā)起連接的方式叫被動(dòng)打開(kāi)(Passive Open),通常服務(wù)器在沒(méi)有客戶端主動(dòng)請(qǐng)求的時(shí)候不知道當(dāng)前有哪個(gè)設(shè)備想向它發(fā)起連接,因此它只能構(gòu)建一個(gè)端口并監(jiān)聽(tīng)該端口,等待客戶端從該端口向它發(fā)起連接請(qǐng)求。在OPEN(打開(kāi))階段無(wú)論是客戶端還是服務(wù)器都需要準(zhǔn)備好TCB數(shù)據(jù)結(jié)構(gòu),但由于服務(wù)器不知道要連接它的客戶端的地址信息,因此在構(gòu)建TCB模塊時(shí)會(huì)默認(rèn)將客戶端對(duì)應(yīng)的Socket數(shù)據(jù)初始化為0。

當(dāng)客戶端和服務(wù)器端雙方都把自己的Socket和TCB數(shù)據(jù)結(jié)構(gòu)準(zhǔn)備好后,雙方就可以進(jìn)入所謂的“三次握手”TCP連接建立過(guò)程。

TCB數(shù)據(jù)結(jié)構(gòu)示意

TCP的頭部信息

TCP頭部

TCP頭部包含20個(gè)字節(jié)的固定首部和長(zhǎng)度可變的最多40個(gè)字節(jié)的填充信息部分(可沒(méi)有)。

  • 最開(kāi)頭的四個(gè)字節(jié)為源端口目的端口,記錄端口信息,再加上位于網(wǎng)絡(luò)層的IP信息頭部中包含的源地址和目標(biāo)地址信息,可唯一確定一個(gè)TCP連接。

  • 再往后的四個(gè)字節(jié)為序號(hào)SYNchronize sequence numbers),值范圍為0到2的32次方減1,標(biāo)示TCP數(shù)據(jù)包中第一個(gè)字節(jié)所存儲(chǔ)內(nèi)容的序號(hào),SYN超過(guò)最大值則回到0重新開(kāi)始,做的是一個(gè)取余(mod)運(yùn)算。

  • 確認(rèn)號(hào)(Acknowledgment number)包含發(fā)送確認(rèn)的一端所期望收到的下一個(gè)序號(hào),因此,確認(rèn)序號(hào)應(yīng)當(dāng)是上次已成功收到數(shù)據(jù)字節(jié)序號(hào)加1。不過(guò),只有當(dāng)標(biāo)志位中的ACK標(biāo)志為1時(shí)該確認(rèn)序列號(hào)的字段才有效。主要用來(lái)解決不丟包的問(wèn)題;

  • 數(shù)據(jù)偏移(offset)表示TCP頭部的32bit字的數(shù)目,offset占四個(gè)bit位,故其最大值為15,這也表示TCP頭部的最大字節(jié)數(shù)為4*15=60個(gè)字節(jié)。

  • 你看到的豎排文字(URG ACK PSH RST SYN FIN)這些都是TCP flags,用于操控TCP狀態(tài)機(jī),表示當(dāng)前的狀態(tài)。

URG:此標(biāo)志表示TCP包的緊急指針域有效,用來(lái)保證TCP連接不被中斷,并且督促中間層設(shè)備要盡快處理這些數(shù)據(jù);

ACK:此標(biāo)志表示應(yīng)答域有效,就是說(shuō)前面所說(shuō)的TCP確認(rèn)號(hào)將會(huì)包含在TCP數(shù)據(jù)包中;ACK這個(gè)Flag有兩個(gè)取值:0和1,為1的時(shí)候表示應(yīng)答域有效,反之無(wú)效;

PSH:這個(gè)標(biāo)志位表示Push操作。所謂Push操作就是指在數(shù)據(jù)包到達(dá)接收端以后,立即傳送給應(yīng)用程序,而不是在緩沖區(qū)中排隊(duì);

RST:這個(gè)標(biāo)志表示連接復(fù)位請(qǐng)求。用來(lái)復(fù)位那些產(chǎn)生錯(cuò)誤的連接,也被用來(lái)拒絕錯(cuò)誤和非法的數(shù)據(jù)包;

SYN:表示同步序號(hào),用來(lái)建立連接。SYN標(biāo)志位和ACK標(biāo)志位搭配使用,當(dāng)連接請(qǐng)求的時(shí)候,SYN=1,ACK=0;連接被響應(yīng)的時(shí)候,SYN=1,ACK=1;這個(gè)標(biāo)志的數(shù)據(jù)包經(jīng)常被用來(lái)進(jìn)行端口掃描。掃描者發(fā)送一個(gè)SYN=1,ACK=0的數(shù)據(jù)包,如果對(duì)方主機(jī)響應(yīng)了一個(gè)SYN+ACK數(shù)據(jù)包回來(lái) ,就表明這臺(tái)主機(jī)存在這個(gè)端口。

FIN: 表示雙方的數(shù)據(jù)傳送完成,沒(méi)有數(shù)據(jù)可以傳送了,四次揮手,發(fā)送FIN標(biāo)志位的TCP數(shù)據(jù)包后,連接將被斷開(kāi)。這個(gè)標(biāo)志的數(shù)據(jù)包也經(jīng)常被用于進(jìn)行端口掃描。

  • 再后面兩個(gè)字節(jié)為窗口大小(window),也就是TCP中的滑動(dòng)窗口——應(yīng)用于TCP的流量控制。比較復(fù)雜,以后再補(bǔ)充。

  • 校驗(yàn)和提高了TCP數(shù)據(jù)傳輸?shù)目煽啃裕?code>緊急指針和URG標(biāo)志位配合使用;再往后就是可選區(qū)域,非必須。


TCP三次握手與四次揮手

TCP為什么要進(jìn)行三次握手,而不是兩次握手?

這個(gè)問(wèn)題在計(jì)算機(jī)網(wǎng)絡(luò)的教材中可以找到答案。在謝希仁著《計(jì)算機(jī)網(wǎng)絡(luò)》第四版中講“三次握手”的目的是,為了防止已失效的連接請(qǐng)求突然又傳送到了服務(wù)器端,不進(jìn)行第三次握手可能會(huì)產(chǎn)生服務(wù)器資源不必要的消耗。

試想,如果只經(jīng)過(guò)兩次握手即建立TCP連接會(huì)怎樣?

栗子:一個(gè)已失去時(shí)間有效期的TCP連接請(qǐng)求報(bào)文被發(fā)送到服務(wù)器端,服務(wù)器此時(shí)并不知道這個(gè)報(bào)文在它的發(fā)送者——客戶端那里已失效,服務(wù)器對(duì)這個(gè)請(qǐng)求報(bào)文做出回應(yīng),并切換到SYN_RCVD狀態(tài),建立TCP連接,而這個(gè)回應(yīng)報(bào)文發(fā)送到客戶端時(shí),客戶端并不會(huì)處理此請(qǐng)求,因?yàn)樗l(fā)出去的請(qǐng)求報(bào)文早已過(guò)期,它沒(méi)有處于SYN_SEND狀態(tài),而服務(wù)器誤以為客戶端已經(jīng)處于此狀態(tài),這樣就會(huì)造成服務(wù)器資源的不必要損耗,由此得出了“三次握手”建立TCP連接的方法。

通過(guò)三次握手,服務(wù)器在接收到失效請(qǐng)求時(shí)也是做出了回應(yīng),但這個(gè)回應(yīng)(SYN/ACK包)如果在一定時(shí)間內(nèi)沒(méi)有收到回應(yīng),則不會(huì)建立TCP連接,資源被釋放;如果服務(wù)器收到了來(lái)自客戶端的回應(yīng),則建立TCP連接。

TCP的三次握手

“三次握手”的作用就是保證客戶端、服務(wù)器端雙方都能明確自己和對(duì)方的收、發(fā)能力是正常的。


image
三次握手

最開(kāi)始的時(shí)候客戶端和服務(wù)器都是處于CLOSED可用狀態(tài)。開(kāi)始建立TCP連接之前,服務(wù)器端的一個(gè)端口已經(jīng)被動(dòng)打開(kāi)(passive open),用于監(jiān)聽(tīng)來(lái)自客戶端的請(qǐng)求,這樣,客戶端的端口可以主動(dòng)打開(kāi)(active open),發(fā)送請(qǐng)求到服務(wù)器端,尋求建立連接。

  • 第一次握手:客戶端向服務(wù)器端發(fā)送SYN包,SYN標(biāo)志位(Flag)置1,包的序號(hào)為客戶端的ISN(Initial Sequence Number),包發(fā)出后,客戶端進(jìn)入SYN_SEND狀態(tài),客戶端知曉客戶端的發(fā)包能力正常;

  • 第二次握手:服務(wù)端接收客戶端發(fā)來(lái)的連接請(qǐng)求,以SYN+ACK包做出回應(yīng),包的SYN標(biāo)志位置1,ACK標(biāo)志位置1,序號(hào)為服務(wù)端的ISN(與客戶端的ISN不同),確認(rèn)碼為客戶端的ISN加1,包發(fā)出后,服務(wù)端進(jìn)入SYN_RCVD狀態(tài),服務(wù)端知曉客戶端的發(fā)包能力正常、服務(wù)端的發(fā)包能力正常,服務(wù)器的收包能力正常;

  • 第三次握手:客戶端接收服務(wù)端發(fā)來(lái)的響應(yīng),以ACK包做出回應(yīng),包的ACK置1,序號(hào)為客戶端的ISN+1,確認(rèn)碼為服務(wù)端的ISN+1,此包發(fā)出后,客戶端轉(zhuǎn)為ESTABLISHED狀態(tài),客戶端知曉服務(wù)端的發(fā)包能力正常,服務(wù)端的收包能力正常、客戶端的收包能力正常。服務(wù)器接收到這個(gè)包后,也進(jìn)入ESTABLISHED狀態(tài),服務(wù)端知曉客戶端的收包能力正常,至此TCP連接被成功建立,可以進(jìn)行數(shù)據(jù)傳輸。

三次握手中的數(shù)據(jù)包只有TCP頭部信息,沒(méi)有主體信息。

TCP協(xié)議規(guī)定,ACK報(bào)文段(ACK標(biāo)志位置1的報(bào)文)可以攜帶數(shù)據(jù),但是如果不攜帶數(shù)據(jù)則不消耗序號(hào),即下一個(gè)報(bào)文的序號(hào)仍為ACK報(bào)文的序號(hào)。

TCP協(xié)議規(guī)定,SYN報(bào)文段(SYN標(biāo)志位置1的報(bào)文,SYN+ACK報(bào)文也屬于這種情況)不能攜帶數(shù)據(jù),但需要消耗掉一個(gè)序號(hào),下一個(gè)發(fā)送的報(bào)文序號(hào)需要+1。


為什么TCP要四次揮手才能互相斷開(kāi)TCP連接?

簡(jiǎn)單來(lái)說(shuō),處于傳輸層的TCP協(xié)議是一個(gè)可靠的協(xié)議,而在它下面,處于網(wǎng)絡(luò)層的IP(Internet Protocol,網(wǎng)絡(luò)協(xié)議)協(xié)議是不可靠的,TCP可靠性的具體體現(xiàn)之一就是四次揮手,不會(huì)出現(xiàn)不必要的錯(cuò)誤和資源損耗。

那四次分手又是為何呢?TCP協(xié)議是一種面向連接的、可靠的、基于字節(jié)流的運(yùn)輸層通信協(xié)議,全雙工模式。

  • 單工(Simplex)通信是指消息只能單方向傳輸?shù)墓ぷ鞣绞健@邕b控、遙測(cè)。

  • 半雙工(Half Duplex)數(shù)據(jù)傳輸指數(shù)據(jù)可以在一個(gè)信號(hào)載體的兩個(gè)方向上傳輸,但是不能同時(shí)傳輸。

  • 全雙工(Full Duplex)通信允許數(shù)據(jù)在兩個(gè)方向上同時(shí)傳輸,它在能力上相當(dāng)于兩個(gè)單工通信方式的結(jié)合。

這就意味著,當(dāng)主機(jī)1發(fā)出FIN報(bào)文段時(shí),只是表示主機(jī)1已經(jīng)沒(méi)有數(shù)據(jù)要發(fā)送了,主機(jī)1告訴主機(jī)2,它的數(shù)據(jù)已經(jīng)全部發(fā)送完畢了;但這時(shí)主機(jī)1還是可以接受來(lái)自主機(jī)2的數(shù)據(jù);當(dāng)主機(jī)2返回ACK報(bào)文段時(shí),表示它已經(jīng)知道主機(jī)1沒(méi)有數(shù)據(jù)發(fā)送了,但是主機(jī)2還是可以發(fā)送數(shù)據(jù)到主機(jī)1的;當(dāng)主機(jī)2也發(fā)送了FIN報(bào)文段時(shí),這個(gè)時(shí)候就表示主機(jī)2也沒(méi)有數(shù)據(jù)要發(fā)送了,就會(huì)告訴主機(jī)1,我也沒(méi)有數(shù)據(jù)要發(fā)送了,之后彼此就會(huì)愉快地?cái)嚅_(kāi)這次TCP連接。

可以看到,如果不經(jīng)過(guò)四次揮手,是不能斷開(kāi)連接的,因?yàn)閷?duì)方那里可能還有數(shù)據(jù)沒(méi)發(fā)送。只有雙方互相確認(rèn)(ACK)了彼此的FIN報(bào)文,TCP連接才能斷開(kāi),TCP才靠得住。

TCP四次揮手

客戶端和服務(wù)器端均可以發(fā)出FIN報(bào)文,即發(fā)出斷開(kāi)連接的請(qǐng)求——表示自己沒(méi)有數(shù)據(jù)要發(fā)送給對(duì)方了,誰(shuí)先發(fā)的誰(shuí)即為主動(dòng)方。

[圖片上傳失敗...(image-308658-1606361336319)]

四次揮手
  • 第一次揮手:主動(dòng)方 向 被動(dòng)方 發(fā)出FIN報(bào)文,序號(hào)為u(等于前面已經(jīng)傳送過(guò)來(lái)的數(shù)據(jù)的最后一個(gè)字節(jié)的序號(hào)加1),確認(rèn)碼為被動(dòng)方的ISN+1,此時(shí)主動(dòng)方進(jìn)入FIN_WAIT_1狀態(tài),等待被動(dòng)方確認(rèn)。

  • 第二次揮手:被動(dòng)方發(fā)送ACK報(bào)文給主動(dòng)方,確認(rèn)主動(dòng)方可以關(guān)閉連接,這個(gè)報(bào)文中序號(hào)為v(由之前已發(fā)出的數(shù)據(jù)序列決定),確認(rèn)碼為u+1,被動(dòng)方發(fā)出ACK報(bào)文后進(jìn)入CLOSE_WAIT狀態(tài),檢查自身是否還有數(shù)據(jù)發(fā)送給對(duì)方——這時(shí)候被動(dòng)方處于半關(guān)閉狀態(tài),即主動(dòng)方已經(jīng)沒(méi)有數(shù)據(jù)要發(fā)送了,但是被動(dòng)方若發(fā)送數(shù)據(jù),主動(dòng)方依然要接收。這個(gè)狀態(tài)還要持續(xù)一段時(shí)間,也就是整個(gè)CLOSE_WAIT狀態(tài)持續(xù)的時(shí)間。主動(dòng)方接收到ACK消息即轉(zhuǎn)入FIN_WAIT_2狀態(tài),繼續(xù)等待被動(dòng)方發(fā)來(lái)的FIN報(bào)文。

  • 第三次揮手:還是被動(dòng)方,被動(dòng)方檢查自身沒(méi)有數(shù)據(jù)要發(fā)給主動(dòng)方了,而在這之前被動(dòng)方很可能又發(fā)送了一些數(shù)據(jù)給主動(dòng)方,假定此時(shí)的序號(hào)為w。被動(dòng)方發(fā)送FIN+ACK報(bào)文給主動(dòng)方,序號(hào)為w,確認(rèn)碼為u+1,發(fā)出后,被動(dòng)方轉(zhuǎn)入LAST_ACK狀態(tài),等待主動(dòng)方關(guān)于斷開(kāi)連接的確認(rèn)。

  • 第四次揮手:主動(dòng)方收到被動(dòng)方發(fā)來(lái)的FIN報(bào)文,回應(yīng)一個(gè)ACK報(bào)文,序號(hào)為u+1,確認(rèn)碼為w+1。發(fā)出后,主動(dòng)方轉(zhuǎn)入TIME_WAIT狀態(tài),將在2?MSL( Maximum Segment Lifetime,最長(zhǎng)報(bào)文段壽命)后斷開(kāi)連接,隨后進(jìn)入CLOSED可用狀態(tài);被動(dòng)方接收到最后的ACK報(bào)文后,隨即斷開(kāi)連接,進(jìn)入CLOSED可用狀態(tài)。

TCP規(guī)定,F(xiàn)IN報(bào)文段要消耗一個(gè)序號(hào),即下一個(gè)把報(bào)文的序號(hào)需+1。

服務(wù)器結(jié)束TCP連接的時(shí)間要比客戶端早一些。

FIN_WAIT_1(主動(dòng)方): FIN_WAIT_1FIN_WAIT_2狀態(tài)都表示等待對(duì)方的FIN報(bào)文。

這兩種狀態(tài)的區(qū)別是:FIN_WAIT_1狀態(tài)實(shí)際上是當(dāng)SOCKET在ESTABLISHED狀態(tài)時(shí),它想主動(dòng)關(guān)閉連接,向?qū)Ψ桨l(fā)送了FIN報(bào)文,此時(shí)該SOCKET即進(jìn)入到FIN_WAIT_1狀態(tài)。而當(dāng)對(duì)方回應(yīng)ACK報(bào)文后,SOCKET方進(jìn)入到FIN_WAIT_2狀態(tài)。

在實(shí)際情況下,無(wú)論對(duì)方何種狀況,都會(huì)馬上回應(yīng)這個(gè)FIN一個(gè)ACK報(bào)文,所以FIN_WAIT_1狀態(tài)一般是比較難捕捉到的,而FIN_WAIT_2狀態(tài)常可以用netstat命令查看。

FIN_WAIT_2(主動(dòng)方):FIN_WAIT_2狀態(tài)下的SOCKET,表示半連接,也即主動(dòng)方要求斷開(kāi)TCP連接,但主動(dòng)方仍需要接收對(duì)方發(fā)來(lái)的FIN報(bào)文,并回應(yīng)一個(gè)ACK報(bào)文。

CLOSE_WAIT(被動(dòng)方):這種狀態(tài)的含義其實(shí)是表示在等待關(guān)閉。怎么理解呢?當(dāng)對(duì)方close一個(gè)SOCKET后發(fā)送FIN報(bào)文給自己,你系統(tǒng)毫無(wú)疑問(wèn)地會(huì)回應(yīng)一個(gè)ACK報(bào)文給對(duì)方,此時(shí)則進(jìn)入到CLOSE_WAIT狀態(tài)。

接下來(lái)你真正需要考慮的,是查看你是否還有數(shù)據(jù)發(fā)送給主動(dòng)方,如果沒(méi)有的話,那么你也就可以 close這個(gè)SOCKET,發(fā)送FIN報(bào)文給對(duì)方,也即關(guān)閉連接。所以你在CLOSE_WAIT狀態(tài)下,需要完成的事情是檢查你還有沒(méi)有數(shù)據(jù)要發(fā)給對(duì)方,沒(méi)有就關(guān)閉連接,發(fā)送FIN報(bào)文告知主動(dòng)方。

LAST_ACK(被動(dòng)方): 是被動(dòng)方在發(fā)送FIN報(bào)文后處于的一個(gè)狀態(tài),即被動(dòng)方已確認(rèn)無(wú)數(shù)據(jù)需要發(fā)送給主動(dòng)方,可以關(guān)閉連接。

被動(dòng)方最后等待主動(dòng)方的ACK報(bào)文。當(dāng)收到ACK報(bào)文后,被動(dòng)方即進(jìn)入CLOSED可用狀態(tài)了。

TIME_WAIT(主動(dòng)方): 表示收到了對(duì)方的FIN報(bào)文,并發(fā)送出了ACK報(bào)文,就等2MSL后主動(dòng)方即可回到CLOSED可用狀態(tài)了。

如果FIN_WAIT_1狀態(tài)下,收到了對(duì)方同時(shí)帶FIN標(biāo)志和ACK標(biāo)志的報(bào)文時(shí),可以直接進(jìn)入到TIME_WAIT狀態(tài),而無(wú)須經(jīng)過(guò)FIN_WAIT_2狀態(tài)。(看圖)

CLOSED: 表示連接已斷開(kāi)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容