TCP網(wǎng)絡(luò)協(xié)議是較常用的及塘,也基本上都會(huì)接觸,那么來(lái)簡(jiǎn)單了解下它吧绵跷。TCP 是一種面向連接的膘螟、可靠的傳輸協(xié)議,它能夠?qū)?shù)據(jù)分成一些小塊碾局,并通過(guò) Internet 進(jìn)行傳輸荆残。在 TCP 中,數(shù)據(jù)被分割成一些稱為 TCP 報(bào)文段(TCP segment)的小塊净当,每個(gè) TCP 報(bào)文段攜帶了一部分?jǐn)?shù)據(jù)内斯,以及一些用于傳輸控制的信息。本文將通過(guò)抓包分析像啼,介紹 TCP 報(bào)文段的結(jié)構(gòu)和各個(gè)字段的含義與解析俘闯。
TCP傳輸層封包描述:
抓包工具
本文使用 Wireshark 作為抓包工具。Wireshark 是一個(gè)流行的開(kāi)源網(wǎng)絡(luò)協(xié)議分析工具忽冻,能夠捕獲和分析網(wǎng)絡(luò)數(shù)據(jù)包真朗。Wireshark 支持多種協(xié)議,包括 TCP僧诚、UDP遮婶、HTTP 等蝗碎。在本文中,我們將使用 Wireshark 抓取并分析 TCP 報(bào)文段旗扑。
抓包分析
下面我們將通過(guò)抓包分析 TCP 報(bào)文段的結(jié)構(gòu)和各個(gè)字段的含義蹦骑。
打開(kāi) Wireshark,選擇一個(gè)合適的接口肩豁,開(kāi)始抓包脊串。在本例中,我們使用的是一個(gè)在局域網(wǎng)中運(yùn)行的 TCP客戶端與服務(wù)端鏈接示例清钥。
選中任意一個(gè) TCP 報(bào)文段琼锋,Wireshark 會(huì)顯示出該數(shù)據(jù)包的詳細(xì)信息,包括 TCP 報(bào)文段的結(jié)構(gòu)和各個(gè)字段的值祟昭。下面是一個(gè) TCP 報(bào)文段的示例(SYNC包缕坎,沒(méi)有帶data):
我們逐一分析每個(gè)字段的含義和解析。
- 源端口號(hào)和目標(biāo)端口號(hào)
源端口號(hào)(Source Port)和目標(biāo)端口號(hào)(Destination Port)用于標(biāo)識(shí)通信的源和目的地應(yīng)用程序篡悟。在本例中谜叹,源端口號(hào)為 12345,目標(biāo)端口號(hào)為 50302搬葬,這表示這是一個(gè)從本地主機(jī)的端口號(hào)為 12345 的應(yīng)用程序向遠(yuǎn)程服務(wù)器的端口號(hào)為 50302 的 TCP 服務(wù)器發(fā)送的數(shù)據(jù)荷腊。
2. 序列號(hào)和確認(rèn)號(hào)
序列號(hào)(Sequence Number):表示本次傳輸數(shù)據(jù)的起始字節(jié)在整個(gè)數(shù)據(jù)流中的位置,用于數(shù)據(jù)的重組和接收方確認(rèn)使用急凰。這里的0是相對(duì)序號(hào)女仰,wireshark自行減去的首次相對(duì)的。原始序號(hào)(Sequence Number (Raw)):2407429255抡锈;
[Next Sequence Numvber:1 指的該方向下一包的序號(hào)疾忍,這個(gè)不在數(shù)據(jù)流中,是wireshark自己解析的
確認(rèn)序號(hào)(Acknowledgment Number): 值為期望收到下一包的序號(hào)床三,用于確認(rèn)已經(jīng)收到數(shù)據(jù)的偏移序號(hào)一罩; 示例中:為0
3. 4位首部長(zhǎng)度(數(shù)據(jù)偏移):占4位,它指出TCP報(bào)文段的數(shù)據(jù)起始處距離TCP報(bào)文段的起始處有多遠(yuǎn)撇簿。這個(gè)字段指出TCP報(bào)文段的首部長(zhǎng)度聂渊。由于首部中還有長(zhǎng)度不確定的選項(xiàng)字段,因此數(shù)據(jù)偏移字段是必要的四瘫,注意汉嗽,“數(shù)據(jù)偏移”的單位是字節(jié)。由于4位二進(jìn)制數(shù)能表示的最大十進(jìn)制數(shù)字是15莲组,因此數(shù)據(jù)偏移的最大值是60字節(jié),這也是TCP首部的最大字節(jié)(即選項(xiàng)長(zhǎng)度不能超過(guò)40字節(jié)=60-20)暖夭。 示例中:這里的首部長(zhǎng)度為8 * 4 = 44字節(jié)
4. 保留位:
5. 標(biāo)志位(按位占用):
(1)緊急URG:當(dāng)URG=1時(shí)锹杈,表明緊急指針字段有效撵孤。它告訴系統(tǒng)此報(bào)文段中有緊急數(shù)據(jù),應(yīng)盡快發(fā)送(相當(dāng)于高優(yōu)先級(jí)的數(shù)據(jù))竭望,而不要按原來(lái)的排隊(duì)順序來(lái)傳送邪码。例如,已經(jīng)發(fā)送了很長(zhǎng)的一個(gè)程序要在遠(yuǎn)地的主機(jī)上運(yùn)行咬清。但后來(lái)發(fā)現(xiàn)了一些問(wèn)題闭专,需要取消該程序的運(yùn)行,因此用戶從鍵盤(pán)發(fā)出中斷命令旧烧。如果不使用緊急數(shù)據(jù)影钉,那么這兩個(gè)字符將存儲(chǔ)在接收TCP的緩存末尾。只有在所有的數(shù)據(jù)被處理完畢后這兩個(gè)字符才被交付接收方的應(yīng)用進(jìn)程掘剪。這樣做就浪費(fèi)了很多時(shí)間平委。當(dāng)URG置為1時(shí),發(fā)送應(yīng)用進(jìn)程就告訴發(fā)送方的TCP有緊急數(shù)據(jù)要傳送夺谁。于是發(fā)送方TCP就把緊急數(shù)據(jù)插入到本報(bào)文段數(shù)據(jù)的最前面廉赔,而在緊急數(shù)據(jù)后面的數(shù)據(jù)仍然是普通數(shù)據(jù)。這時(shí)要與首部中緊急指針(Urgent Pointer)字段配合使用匾鸥。
(2)確認(rèn)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:當(dāng)兩個(gè)應(yīng)用進(jìn)程進(jìn)行交互式的通信時(shí),有時(shí)在一端的應(yīng)用進(jìn)程希望在鍵入一個(gè)命令后立即就能收到對(duì)方的響應(yīng)笆环。在這種情況下攒至,TCP就可以使用推送(push)操作。這時(shí)躁劣,發(fā)送方TCP把PSH置為1迫吐,并立即創(chuàng)建一個(gè)報(bào)文段發(fā)送出去。接收方TCP收到PSH=1的報(bào)文段账忘,就盡快地(即“推送”向前)交付接收應(yīng)用進(jìn)程志膀。而不用再等到整個(gè)緩存都填滿了后再向上交付。一般這個(gè)不需要手動(dòng)執(zhí)標(biāo)志鳖擒,TCP默認(rèn)實(shí)現(xiàn)溉浙;
(4)復(fù)位RST:當(dāng)RST=1時(shí),表名TCP連接中出現(xiàn)了嚴(yán)重錯(cuò)誤(如由于主機(jī)崩潰或其他原因)蒋荚,必須釋放連接戳稽,然后再重新建立傳輸連接。RST置為1還用來(lái)拒絕一個(gè)非法的報(bào)文段或拒絕打開(kāi)一個(gè)連接。
(5)同步SYN:在連接建立時(shí)用來(lái)同步序號(hào)惊奇。當(dāng)SYN=1而ACK=0時(shí)互躬,表明這是一個(gè)連接請(qǐng)求報(bào)文段。對(duì)方若同意建立連接颂郎,則應(yīng)在響應(yīng)的報(bào)文段中使SYN=1和ACK=1吼渡,因此SYN置為1就表示這是一個(gè)連接請(qǐng)求或連接接受報(bào)文。
(6)終止FIN:發(fā)送端完成任務(wù)乓序,表要求釋放運(yùn)輸連接寺酪。
示例中,是將SYN標(biāo)志給執(zhí)了起來(lái)替劈;
6. 窗口:接收方的流量控制手段寄雀,窗口大小為字節(jié)數(shù),起始于確認(rèn)序號(hào)字段指明的值抬纸,這個(gè)值是接收端正期望接收的字節(jié)咙俩。告訴發(fā)送端,接收端目前允許發(fā)送端數(shù)據(jù)量湿故。大小兩字節(jié)65535阿趁,在客戶端與服務(wù)端TCP都允許的情況下,選項(xiàng)中可存在窗口擴(kuò)展選項(xiàng)坛猪。 示例中:窗口大小65535脖阵,代表告訴發(fā)送方,從這個(gè)下一包0的序號(hào)開(kāi)始墅茉,接收方只能接受65535個(gè)字節(jié)長(zhǎng)度了(當(dāng)然這里還沒(méi)有算上擴(kuò)展選項(xiàng)命黔,稍后再講)
7. 校驗(yàn)和:2字節(jié),檢驗(yàn)和覆蓋了整個(gè)的TCP報(bào)文段: TCP首部和TCP數(shù)據(jù)就斤。這是一個(gè)強(qiáng)制性的字段悍募,一定是由發(fā)端計(jì)算和存儲(chǔ),并由收端進(jìn)行驗(yàn)證洋机。和UDP用戶數(shù)據(jù)報(bào)一樣坠宴,在計(jì)算檢驗(yàn)和時(shí),要在TCP報(bào)文段的前面加上12字節(jié)的偽首部绷旗。偽首部的格式和UDP用戶數(shù)據(jù)報(bào)的偽首部一樣喜鼓。但應(yīng)把偽首部第4個(gè)字段中的17改為6(TCP的協(xié)議號(hào)是6);把第5字段中的UDP中的長(zhǎng)度改為T(mén)CP長(zhǎng)度衔肢。接收方收到此報(bào)文段后庄岖,仍要加上這個(gè)偽首部來(lái)計(jì)算檢驗(yàn)和。若使用TPv6,則相應(yīng)的偽首部也要改變角骤。 示例中:0xfe34
8. 緊急指針:2字節(jié)隅忿,在緊急URG標(biāo)志執(zhí)1的時(shí)候有效,代表一個(gè)偏移量,和序號(hào)字段值相加背桐,代表緊急數(shù)據(jù)最后一個(gè)字節(jié)的序號(hào)刘陶。示例中: 為0
9. 選項(xiàng):長(zhǎng)度可變,最長(zhǎng)可達(dá)40字節(jié)牢撼。當(dāng)沒(méi)有使用“選項(xiàng)”時(shí),TCP的首部長(zhǎng)度是20字節(jié)疑苫。其最大長(zhǎng)度可根據(jù)TCP首部長(zhǎng)度進(jìn)行推算熏版。TCP首部長(zhǎng)度用4位表示,那么選項(xiàng)部分最長(zhǎng)為:(2^4-1)*4-20=40字節(jié)捍掺。以下講下最常見(jiàn)的一些選項(xiàng):
本次選項(xiàng)中看到有24字節(jié)
9.1 MSS(最大報(bào)文段長(zhǎng)度-Maxium Segment Size):MSS是每一個(gè)TCP報(bào)文段中的數(shù)據(jù)字段的最大長(zhǎng)度撼短。數(shù)據(jù)字段加上TCP首部才等于整個(gè)的TCP報(bào)文段。所以MSS并不是整個(gè)TCP報(bào)文段的最大長(zhǎng)度挺勿,而是“TCP報(bào)文段長(zhǎng)度減去TCP首部長(zhǎng)度”曲横。
為什么要有MSS:為了增加網(wǎng)絡(luò)利用率
一般說(shuō)來(lái),如果沒(méi)有分段發(fā)生不瓶, MSS大部分時(shí)候還是越大越好禾嫉。報(bào)文段越大允許每個(gè)報(bào)文段傳送的數(shù)據(jù)就越多,相對(duì)IP和TCP首部有更高的網(wǎng)絡(luò)利用率蚊丐。則MSS的默認(rèn)值是536字節(jié)長(zhǎng)(這個(gè)默認(rèn)值允許20字節(jié)的IP首部和20字節(jié)的TCP首部以適合576字節(jié)IP數(shù)據(jù)報(bào))
本示例中:MSS為16344
9.2 其他選項(xiàng):
- 窗口擴(kuò)大選項(xiàng)(Windows Scaling):是為了擴(kuò)大窗口熙参。我們知道,TCP首部中窗口字段長(zhǎng)度是16位麦备,因此最大的窗口大小為64K字節(jié)孽椰。雖然這對(duì)早期的網(wǎng)絡(luò)是足夠用的,但對(duì)于包含衛(wèi)星信道的網(wǎng)絡(luò)凛篙,傳播時(shí)延和寬帶都很大黍匾,要獲得高吞吐量需要更大的窗口大小。
(1)窗口擴(kuò)大選項(xiàng)占3字節(jié)呛梆,其中第一字節(jié)代表類型锐涯,第二字節(jié)代表長(zhǎng)度,第三字節(jié)(shift count)則是擴(kuò)展移位值S了削彬,新的窗口值等于TCP首部中的窗口位數(shù)從16增大到(16+S)全庸。移位值允許使用的最大值是14,相當(dāng)于窗口最大值增大到2(16+14)-1=230-1融痛。
(2)窗口擴(kuò)大選項(xiàng)可以在雙方初始建立TCP連接時(shí)進(jìn)行協(xié)商壶笼。如果連接的某一端實(shí)現(xiàn)了窗口擴(kuò)大,當(dāng)它不再需要擴(kuò)大其窗口時(shí)雁刷,可發(fā)送S=0選項(xiàng)覆劈,使窗口大小回到16。
本示例中:窗口擴(kuò)大選項(xiàng)則是移位6,等于擴(kuò)展了64倍(65565 * 2^6)
- 時(shí)間戳選項(xiàng)(Timestamps):占10字節(jié)责语,其中最主要的字段是時(shí)間戳字段(4字節(jié))和時(shí)間戳回送回答字段(4字節(jié))炮障。時(shí)間戳選項(xiàng)有以下兩個(gè)概念:
(1)用來(lái)計(jì)算往返時(shí)間RTT(往返時(shí)間)。發(fā)送方在發(fā)送報(bào)文段時(shí)把當(dāng)前時(shí)鐘的時(shí)間值放入時(shí)間戳字段坤候,接收方在確認(rèn)該報(bào)文段時(shí)把時(shí)間戳字段復(fù)制到時(shí)間戳回送回答字段胁赢。因此,發(fā)送方在收到確認(rèn)報(bào)文后白筹,可以準(zhǔn)確地計(jì)算出RTT來(lái)智末。為了減少任一端所維持的狀態(tài)數(shù)量,對(duì)于每個(gè)連接只保持一個(gè)時(shí)間戳的數(shù)值徒河。選擇何時(shí)系馆,更新這個(gè)數(shù)值的算法非常簡(jiǎn)單(《TCP/IP詳解》):
1 ) T C P 跟蹤下一個(gè) A C K 中將要發(fā)送的時(shí)間戳的值(一個(gè)名為 t s re c e n t 的 變 量 ) 以 及 最 后 發(fā) 送的 A C K 中的確認(rèn)序號(hào)(一個(gè)名為 l a s t a c k的變量)。這個(gè)序號(hào)就是接收方期望的序號(hào)顽照。
當(dāng)一個(gè)包含有字節(jié)號(hào) l a s t a c k的報(bào)文段到達(dá)時(shí)由蘑,則該報(bào)文段中的時(shí)間戳被保存在 t s re c e n t 中。
無(wú)論何時(shí)發(fā)送一個(gè)時(shí)間戳選項(xiàng)代兵, t s re c e n t就 作 為 時(shí) 間 戳 回 顯 應(yīng) 答 字 段 被 發(fā) 送 尼酿, 而 序 號(hào) 字 段被保存在 l a s t a c k 中。 (2)用于處理防止序號(hào)繞回PAWS(TCP序號(hào)超過(guò)232的情況):TCP報(bào)文段的序號(hào)只有32位植影,而每增加232個(gè)序號(hào)就會(huì)重復(fù)使用原來(lái)用過(guò)的序號(hào)谓媒。當(dāng)使用高速網(wǎng)絡(luò)時(shí),在一次TCP連接的數(shù)據(jù)傳送中序號(hào)很可能被重復(fù)使用何乎。為了使接收方能夠把新的報(bào)文段和遲到很久的報(bào)文段區(qū)分開(kāi)句惯,則可以在報(bào)文段中加上這種時(shí)間戳。
本示例中: 發(fā)送的3588061560支救,因?yàn)槭堑谝粋€(gè)SYN所以回復(fù)的是0
- NOP(NO-Operation):它要求選項(xiàng)部分中的每種選項(xiàng)長(zhǎng)度必須是4字節(jié)的倍數(shù)抢野,不足的則用NOP填充。同時(shí)也可以用來(lái)分割不同的選項(xiàng)字段各墨。如窗口擴(kuò)大選項(xiàng)和SACK之間用NOP隔開(kāi)
至此指孤,一個(gè)SYN包就解析完了,對(duì)于PSH贬堵、ACK解析類似哦