TCP報(bào)文格式
TCP提供一種面向連接的,可靠的字節(jié)流服務(wù)。
TCP首部的數(shù)據(jù)格式如下。(如果不計(jì)任選字段,通常是20個(gè)字節(jié))

字段分析
源端口:源端口和IP地址的作用是標(biāo)識(shí)報(bào)文的返回地址。
目的端口:端口指明接收方計(jì)算機(jī)上的應(yīng)用程序接口。
TCP報(bào)頭中的源端口號(hào)和目的端口號(hào)同IP數(shù)據(jù)報(bào)中的源IP與目的IP唯一確定一條TCP連接。
序號(hào):是TCP可靠傳輸?shù)年P(guān)鍵部分。序號(hào)是該報(bào)文段發(fā)送的數(shù)據(jù)組的第一個(gè)字節(jié)的序號(hào)。在TCP傳送的流中,每一個(gè)字節(jié)都有一個(gè)序號(hào)。比如一個(gè)報(bào)文段的序號(hào)為300,報(bào)文段數(shù)據(jù)部分共有100字節(jié),則下一個(gè)報(bào)文段的序號(hào)為400。所以序號(hào)確保了TCP傳輸?shù)挠行蛐浴?/p>
確認(rèn)號(hào):即ACK,指明下一個(gè)期待收到的字節(jié)序號(hào),表明該序號(hào)之前的所有數(shù)據(jù)已經(jīng)正確無誤的收到。確認(rèn)號(hào)只有當(dāng)ACK標(biāo)志為1時(shí)才有效。比如建立連接時(shí),SYN報(bào)文的ACK標(biāo)志位為0。
首部長(zhǎng)度/數(shù)據(jù)偏移:占4位,它指出TCP報(bào)文的數(shù)據(jù)距離TCP報(bào)文段的起始處有多遠(yuǎn)。由于首部可能含有可選項(xiàng)內(nèi)容,因此TCP報(bào)頭的長(zhǎng)度是不確定的,報(bào)頭不包含任何任選字段則長(zhǎng)度為20字節(jié),4位首部長(zhǎng)度字段所能表示的最大值為1111,轉(zhuǎn)化為10進(jìn)制為15,15*32/8=60,故報(bào)頭最大長(zhǎng)度為60字節(jié)。首部長(zhǎng)度也叫數(shù)據(jù)偏移,是因?yàn)槭撞块L(zhǎng)度實(shí)際上指示了數(shù)據(jù)區(qū)在報(bào)文段中的起始偏移值。
保留:占6位,保留今后使用,但目前應(yīng)都位0。
控制位:URG ACK PSH RST SYN FIN,共6個(gè),每一個(gè)標(biāo)志位表示一個(gè)控制功能。
緊急URG:當(dāng)URG=1,表明緊急指針字段有效。告訴系統(tǒng)此報(bào)文段中有緊急數(shù)據(jù)
確認(rèn)ACK:僅當(dāng)ACK=1時(shí),確認(rèn)號(hào)字段才有效。TCP規(guī)定,在連接建立后所有報(bào)文的傳輸都必須把ACK置1。
推送PSH:當(dāng)兩個(gè)應(yīng)用進(jìn)程進(jìn)行交互式通信時(shí),有時(shí)在一端的應(yīng)用進(jìn)程希望在鍵入一個(gè)命令后立即就能收到對(duì)方的響應(yīng),這時(shí)候就將PSH=1。
復(fù)位RST:當(dāng)RST=1,表明TCP連接中出現(xiàn)嚴(yán)重差錯(cuò),必須釋放連接,然后再重新建立連接。
同步SYN:在連接建立時(shí)用來同步序號(hào)。當(dāng)SYN=1,ACK=0,表明是連接請(qǐng)求報(bào)文,若同意連接,則響應(yīng)報(bào)文中應(yīng)該使SYN=1,ACK=1。
終止FIN:用來釋放連接。當(dāng)FIN=1,表明此報(bào)文的發(fā)送方的數(shù)據(jù)已經(jīng)發(fā)送完畢,并且要求釋放。
窗口:滑動(dòng)窗口大小,用來告知發(fā)送端接受端的緩存大小,以此控制發(fā)送端發(fā)送數(shù)據(jù)的速率,從而達(dá)到流量控制。窗口大小時(shí)一個(gè)16bit字段,因而窗口大小最大為65535。
校驗(yàn)和:奇偶校驗(yàn),此校驗(yàn)和是對(duì)整個(gè)的 TCP 報(bào)文段,包括 TCP 頭部和 TCP 數(shù)據(jù),以 16 位字進(jìn)行計(jì)算所得。由發(fā)送端計(jì)算和存儲(chǔ),并由接收端進(jìn)行驗(yàn)證。
緊急指針:只有當(dāng) URG 標(biāo)志置 1 時(shí)緊急指針才有效。緊急指針是一個(gè)正的偏移量,和順序號(hào)字段中的值相加表示緊急數(shù)據(jù)最后一個(gè)字節(jié)的序號(hào)。 TCP 的緊急方式是發(fā)送端向另一端發(fā)送緊急數(shù)據(jù)的一種方式。
選項(xiàng)和填充:最常見的可選字段是最長(zhǎng)報(bào)文大小,又稱為MSS(Maximum Segment Size),每個(gè)連接方通常都在通信的第一個(gè)報(bào)文段(為建立連接而設(shè)置SYN標(biāo)志為1的那個(gè)段)中指明這個(gè)選項(xiàng),它表示本端所能接受的最大報(bào)文段的長(zhǎng)度。選項(xiàng)長(zhǎng)度不一定是32位的整數(shù)倍,所以要加填充位,即在這個(gè)字段中加入額外的零,以保證TCP頭是32的整數(shù)倍。
數(shù)據(jù)部分:?TCP 報(bào)文段中的數(shù)據(jù)部分是可選的。在一個(gè)連接建立和一個(gè)連接終止時(shí),雙方交換的報(bào)文段僅有 TCP 首部。如果一方?jīng)]有數(shù)據(jù)要發(fā)送,也使用沒有任何數(shù)據(jù)的首部來確認(rèn)收到的數(shù)據(jù)。在處理超時(shí)的許多情況中,也會(huì)發(fā)送不帶任何數(shù)據(jù)的報(bào)文段。
三次握手
第一次握手:客戶端發(fā)送syn包(syn=x)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn);
第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=x+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=y),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=y+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手。
握手過程中傳送的包里不包含數(shù)據(jù),三次握手完畢后,客戶端與服務(wù)器才正式開始傳送數(shù)據(jù)。理想狀態(tài)下,TCP連接一旦建立,在通信雙方中的任何一方主動(dòng)關(guān)閉連接之前,TCP 連接都將被一直保持下去。

為什么會(huì)采用三次握手,若采用二次握手可以嗎? 四次呢?
建立連接的過程是利用客戶服務(wù)器模式,假設(shè)主機(jī)A為客戶端,主機(jī)B為服務(wù)器端。
采用三次握手是為了防止失效的連接請(qǐng)求報(bào)文段突然又傳送到主機(jī)B,因而產(chǎn)生錯(cuò)誤。
失效的連接請(qǐng)求報(bào)文段是指:主機(jī)A發(fā)出的連接請(qǐng)求沒有收到主機(jī)B的確認(rèn),于是經(jīng)過一段時(shí)間后,主機(jī)A又重新向主機(jī)B發(fā)送連接請(qǐng)求,且建立成功,順序完成數(shù)據(jù)傳輸??紤]這樣一種特殊情況,主機(jī)A第一次發(fā)送的連接請(qǐng)求并沒有丟失,而是因?yàn)榫W(wǎng)絡(luò)節(jié)點(diǎn)導(dǎo)致延遲達(dá)到主機(jī)B,主機(jī)B以為是主機(jī)A又發(fā)起的新連接,于是主機(jī)B同意連接,并向主機(jī)A發(fā)回確認(rèn),但是此時(shí)主機(jī)A根本不會(huì)理會(huì),主機(jī)B就一直在等待主機(jī)A發(fā)送數(shù)據(jù),導(dǎo)致主機(jī)B的資源浪費(fèi)。
采用兩次握手不行,原因就是上面說的失效的連接請(qǐng)求的特殊情況。而在三次握手中, client和server都有一個(gè)發(fā)syn和收ack的過程, 雙方都是發(fā)后能收, 表明通信則準(zhǔn)備工作OK。
為什么不是四次握手呢? 大家應(yīng)該知道通信中著名的藍(lán)軍紅軍約定, 這個(gè)例子說明, 通信不可能100%可靠, 而上面的三次握手已經(jīng)做好了通信的準(zhǔn)備工作, 再增加握手, 并不能顯著提高可靠性, 而且也沒有必要。
四次揮手
數(shù)據(jù)傳輸完畢后,雙方都可釋放連接。最開始的時(shí)候,客戶端和服務(wù)器都是處于ESTABLISHED狀態(tài),假設(shè)客戶端主動(dòng)關(guān)閉,服務(wù)器被動(dòng)關(guān)閉。

第一次揮手:客戶端發(fā)送一個(gè)FIN,用來關(guān)閉客戶端到服務(wù)器的數(shù)據(jù)傳送,也就是客戶端告訴服務(wù)器:我已經(jīng)不 會(huì)再給你發(fā)數(shù)據(jù)了(當(dāng)然,在fin包之前發(fā)送出去的數(shù)據(jù),如果沒有收到對(duì)應(yīng)的ack確認(rèn)報(bào)文,客戶端依然會(huì)重發(fā)這些數(shù)據(jù)),但是,此時(shí)客戶端還可 以接受數(shù)據(jù)。
FIN=1,其序列號(hào)為seq=u(等于前面已經(jīng)傳送過來的數(shù)據(jù)的最后一個(gè)字節(jié)的序號(hào)加1),此時(shí),客戶端進(jìn)入FIN-WAIT-1(終止等待1)狀態(tài)。 TCP規(guī)定,F(xiàn)IN報(bào)文段即使不攜帶數(shù)據(jù),也要消耗一個(gè)序號(hào)。
第二次揮手:服務(wù)器收到FIN包后,發(fā)送一個(gè)ACK給對(duì)方并且?guī)献约旱男蛄刑?hào)seq,確認(rèn)序號(hào)為收到序號(hào)+1(與SYN相同,一個(gè)FIN占用一個(gè)序號(hào))。此時(shí),服務(wù)端就進(jìn)入了CLOSE-WAIT(關(guān)閉等待)狀態(tài)。TCP服務(wù)器通知高層的應(yīng)用進(jìn)程,客戶端向服務(wù)器的方向就釋放了,這時(shí)候處于半關(guān)閉狀態(tài),即客戶端已經(jīng)沒有數(shù)據(jù)要發(fā)送了,但是服務(wù)器若發(fā)送數(shù)據(jù),客戶端依然要接受。這個(gè)狀態(tài)還要持續(xù)一段時(shí)間,也就是整個(gè)CLOSE-WAIT狀態(tài)持續(xù)的時(shí)間。
此時(shí),客戶端就進(jìn)入FIN-WAIT-2(終止等待2)狀態(tài),等待服務(wù)器發(fā)送連接釋放報(bào)文(在這之前還需要接受服務(wù)器發(fā)送的最后的數(shù)據(jù))。
第三次揮手:服務(wù)器發(fā)送一個(gè)FIN,用來關(guān)閉服務(wù)器到客戶端的數(shù)據(jù)傳送,也就是告訴客戶端,我的數(shù)據(jù)也發(fā)送完了,不會(huì)再給你發(fā)數(shù)據(jù)了。由于在半關(guān)閉狀態(tài),服務(wù)器很可能又發(fā)送了一些數(shù)據(jù),假定此時(shí)的序列號(hào)為seq=w,此時(shí),服務(wù)器就進(jìn)入了LAST-ACK(最后確認(rèn))狀態(tài),等待客戶端的確認(rèn)。
第四次揮手:主動(dòng)關(guān)閉方收到FIN后,發(fā)送一個(gè)ACK給被動(dòng)關(guān)閉方,確認(rèn)序號(hào)為收到序號(hào)+1,此時(shí),客戶端就進(jìn)入了TIME-WAIT(時(shí)間等待)狀態(tài)。注意此時(shí)TCP連接還沒有釋放,必須經(jīng)過2?MSL(最長(zhǎng)報(bào)文段壽命)的時(shí)間后,當(dāng)客戶端撤銷相應(yīng)的TCB后,才進(jìn)入CLOSED狀態(tài)。
服務(wù)器只要收到了客戶端發(fā)出的確認(rèn),立即進(jìn)入CLOSED狀態(tài)。同樣,撤銷TCB后,就結(jié)束了這次的TCP連接??梢钥吹剑?wù)器結(jié)束TCP連接的時(shí)間要比客戶端早一些。至此,完成四次揮手。
為什么客戶端最后還要等待2MSL?
MSL(Maximum Segment Lifetime),TCP允許不同的實(shí)現(xiàn)可以設(shè)置不同的MSL值。
第一,保證客戶端發(fā)送的最后一個(gè)ACK報(bào)文能夠到達(dá)服務(wù)器,因?yàn)檫@個(gè)ACK報(bào)文可能丟失,站在服務(wù)器的角度看來,我已經(jīng)發(fā)送了FIN+ACK報(bào)文請(qǐng)求斷開了,客戶端還沒有給我回應(yīng),應(yīng)該是我發(fā)送的請(qǐng)求斷開報(bào)文它沒有收到,于是服務(wù)器又會(huì)重新發(fā)送一次,而客戶端就能在這個(gè)2MSL時(shí)間段內(nèi)收到這個(gè)重傳的報(bào)文,接著給出回應(yīng)報(bào)文,并且會(huì)重啟2MSL計(jì)時(shí)器。
第二,防止類似與“三次握手”中提到了的“已經(jīng)失效的連接請(qǐng)求報(bào)文段”出現(xiàn)在本連接中??蛻舳税l(fā)送完最后一個(gè)確認(rèn)報(bào)文后,在這個(gè)2MSL時(shí)間中,就可以使本連接持續(xù)的時(shí)間內(nèi)所產(chǎn)生的所有報(bào)文段都從網(wǎng)絡(luò)中消失。這樣新的連接中不會(huì)出現(xiàn)舊連接的請(qǐng)求報(bào)文。
為什么建立連接是三次握手,關(guān)閉連接確是四次揮手呢?
建立連接的時(shí)候, 服務(wù)器在LISTEN狀態(tài)下,收到建立連接請(qǐng)求的SYN報(bào)文后,把ACK和SYN放在一個(gè)報(bào)文里發(fā)送給客戶端。
而關(guān)閉連接時(shí),服務(wù)器收到對(duì)方的FIN報(bào)文時(shí),僅僅表示對(duì)方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù),而自己也未必全部數(shù)據(jù)都發(fā)送給對(duì)方了,所以己方可以立即關(guān)閉,也可以發(fā)送一些數(shù)據(jù)給對(duì)方后,再發(fā)送FIN報(bào)文給對(duì)方來表示同意現(xiàn)在關(guān)閉連接,因此,己方ACK和FIN一般都會(huì)分開發(fā)送,從而導(dǎo)致多了一次。
轉(zhuǎn)自:https://www.javazhiyin.com/1693.html