TCP網(wǎng)絡(luò)協(xié)議是較常用的,也基本上都會接觸,那么來簡單了解下它吧。TCP 是一種面向連接的、可靠的傳輸協(xié)議,它能夠?qū)?shù)據(jù)分成一些小塊,并通過 Internet 進(jìn)行傳輸。在 TCP 中,數(shù)據(jù)被分割成一些稱為 TCP 報文段(TCP segment)的小塊,每個 TCP 報文段攜帶了一部分?jǐn)?shù)據(jù),以及一些用于傳輸控制的信息。本文將通過抓包分析,介紹 TCP 報文段的結(jié)構(gòu)和各個字段的含義與解析。
TCP傳輸層封包描述:

抓包工具
本文使用 Wireshark 作為抓包工具。Wireshark 是一個流行的開源網(wǎng)絡(luò)協(xié)議分析工具,能夠捕獲和分析網(wǎng)絡(luò)數(shù)據(jù)包。Wireshark 支持多種協(xié)議,包括 TCP、UDP、HTTP 等。在本文中,我們將使用 Wireshark 抓取并分析 TCP 報文段。
抓包分析
下面我們將通過抓包分析 TCP 報文段的結(jié)構(gòu)和各個字段的含義。
打開 Wireshark,選擇一個合適的接口,開始抓包。在本例中,我們使用的是一個在局域網(wǎng)中運行的 TCP客戶端與服務(wù)端鏈接示例。
選中任意一個 TCP 報文段,Wireshark 會顯示出該數(shù)據(jù)包的詳細(xì)信息,包括 TCP 報文段的結(jié)構(gòu)和各個字段的值。下面是一個 TCP 報文段的示例(SYNC包,沒有帶data):

我們逐一分析每個字段的含義和解析。
- 源端口號和目標(biāo)端口號
源端口號(Source Port)和目標(biāo)端口號(Destination Port)用于標(biāo)識通信的源和目的地應(yīng)用程序。在本例中,源端口號為 12345,目標(biāo)端口號為 50302,這表示這是一個從本地主機的端口號為 12345 的應(yīng)用程序向遠(yuǎn)程服務(wù)器的端口號為 50302 的 TCP 服務(wù)器發(fā)送的數(shù)據(jù)。
2. 序列號和確認(rèn)號
序列號(Sequence Number):表示本次傳輸數(shù)據(jù)的起始字節(jié)在整個數(shù)據(jù)流中的位置,用于數(shù)據(jù)的重組和接收方確認(rèn)使用。這里的0是相對序號,wireshark自行減去的首次相對的。原始序號(Sequence Number (Raw)):2407429255;
[Next Sequence Numvber:1 指的該方向下一包的序號,這個不在數(shù)據(jù)流中,是wireshark自己解析的
確認(rèn)序號(Acknowledgment Number): 值為期望收到下一包的序號,用于確認(rèn)已經(jīng)收到數(shù)據(jù)的偏移序號; 示例中:為0
3. 4位首部長度(數(shù)據(jù)偏移):占4位,它指出TCP報文段的數(shù)據(jù)起始處距離TCP報文段的起始處有多遠(yuǎn)。這個字段指出TCP報文段的首部長度。由于首部中還有長度不確定的選項字段,因此數(shù)據(jù)偏移字段是必要的,注意,“數(shù)據(jù)偏移”的單位是字節(jié)。由于4位二進(jìn)制數(shù)能表示的最大十進(jìn)制數(shù)字是15,因此數(shù)據(jù)偏移的最大值是60字節(jié),這也是TCP首部的最大字節(jié)(即選項長度不能超過40字節(jié)=60-20)。 示例中:這里的首部長度為8 * 4 = 44字節(jié)
4. 保留位:
5. 標(biāo)志位(按位占用):
(1)緊急URG:當(dāng)URG=1時,表明緊急指針字段有效。它告訴系統(tǒng)此報文段中有緊急數(shù)據(jù),應(yīng)盡快發(fā)送(相當(dāng)于高優(yōu)先級的數(shù)據(jù)),而不要按原來的排隊順序來傳送。例如,已經(jīng)發(fā)送了很長的一個程序要在遠(yuǎn)地的主機上運行。但后來發(fā)現(xiàn)了一些問題,需要取消該程序的運行,因此用戶從鍵盤發(fā)出中斷命令。如果不使用緊急數(shù)據(jù),那么這兩個字符將存儲在接收TCP的緩存末尾。只有在所有的數(shù)據(jù)被處理完畢后這兩個字符才被交付接收方的應(yīng)用進(jìn)程。這樣做就浪費了很多時間。當(dāng)URG置為1時,發(fā)送應(yīng)用進(jìn)程就告訴發(fā)送方的TCP有緊急數(shù)據(jù)要傳送。于是發(fā)送方TCP就把緊急數(shù)據(jù)插入到本報文段數(shù)據(jù)的最前面,而在緊急數(shù)據(jù)后面的數(shù)據(jù)仍然是普通數(shù)據(jù)。這時要與首部中緊急指針(Urgent Pointer)字段配合使用。
(2)確認(rèn)ACK: 僅當(dāng)ACK = 1時確認(rèn)號字段才有效,當(dāng)ACK = 0時確認(rèn)號無效。TCP規(guī)定,在連接建立后所有的傳送的報文段都必須把ACK置為1。
(3)推送PSH:當(dāng)兩個應(yīng)用進(jìn)程進(jìn)行交互式的通信時,有時在一端的應(yīng)用進(jìn)程希望在鍵入一個命令后立即就能收到對方的響應(yīng)。在這種情況下,TCP就可以使用推送(push)操作。這時,發(fā)送方TCP把PSH置為1,并立即創(chuàng)建一個報文段發(fā)送出去。接收方TCP收到PSH=1的報文段,就盡快地(即“推送”向前)交付接收應(yīng)用進(jìn)程。而不用再等到整個緩存都填滿了后再向上交付。一般這個不需要手動執(zhí)標(biāo)志,TCP默認(rèn)實現(xiàn);
(4)復(fù)位RST:當(dāng)RST=1時,表名TCP連接中出現(xiàn)了嚴(yán)重錯誤(如由于主機崩潰或其他原因),必須釋放連接,然后再重新建立傳輸連接。RST置為1還用來拒絕一個非法的報文段或拒絕打開一個連接。
(5)同步SYN:在連接建立時用來同步序號。當(dāng)SYN=1而ACK=0時,表明這是一個連接請求報文段。對方若同意建立連接,則應(yīng)在響應(yīng)的報文段中使SYN=1和ACK=1,因此SYN置為1就表示這是一個連接請求或連接接受報文。
(6)終止FIN:發(fā)送端完成任務(wù),表要求釋放運輸連接。
示例中,是將SYN標(biāo)志給執(zhí)了起來;

6. 窗口:接收方的流量控制手段,窗口大小為字節(jié)數(shù),起始于確認(rèn)序號字段指明的值,這個值是接收端正期望接收的字節(jié)。告訴發(fā)送端,接收端目前允許發(fā)送端數(shù)據(jù)量。大小兩字節(jié)65535,在客戶端與服務(wù)端TCP都允許的情況下,選項中可存在窗口擴展選項。 示例中:窗口大小65535,代表告訴發(fā)送方,從這個下一包0的序號開始,接收方只能接受65535個字節(jié)長度了(當(dāng)然這里還沒有算上擴展選項,稍后再講)
7. 校驗和:2字節(jié),檢驗和覆蓋了整個的TCP報文段: TCP首部和TCP數(shù)據(jù)。這是一個強制性的字段,一定是由發(fā)端計算和存儲,并由收端進(jìn)行驗證。和UDP用戶數(shù)據(jù)報一樣,在計算檢驗和時,要在TCP報文段的前面加上12字節(jié)的偽首部。偽首部的格式和UDP用戶數(shù)據(jù)報的偽首部一樣。但應(yīng)把偽首部第4個字段中的17改為6(TCP的協(xié)議號是6);把第5字段中的UDP中的長度改為TCP長度。接收方收到此報文段后,仍要加上這個偽首部來計算檢驗和。若使用TPv6,則相應(yīng)的偽首部也要改變。 示例中:0xfe34
8. 緊急指針:2字節(jié),在緊急URG標(biāo)志執(zhí)1的時候有效,代表一個偏移量,和序號字段值相加,代表緊急數(shù)據(jù)最后一個字節(jié)的序號。示例中: 為0
9. 選項:長度可變,最長可達(dá)40字節(jié)。當(dāng)沒有使用“選項”時,TCP的首部長度是20字節(jié)。其最大長度可根據(jù)TCP首部長度進(jìn)行推算。TCP首部長度用4位表示,那么選項部分最長為:(2^4-1)*4-20=40字節(jié)。以下講下最常見的一些選項:
本次選項中看到有24字節(jié)

9.1 MSS(最大報文段長度-Maxium Segment Size):MSS是每一個TCP報文段中的數(shù)據(jù)字段的最大長度。數(shù)據(jù)字段加上TCP首部才等于整個的TCP報文段。所以MSS并不是整個TCP報文段的最大長度,而是“TCP報文段長度減去TCP首部長度”。
為什么要有MSS:為了增加網(wǎng)絡(luò)利用率
一般說來,如果沒有分段發(fā)生, MSS大部分時候還是越大越好。報文段越大允許每個報文段傳送的數(shù)據(jù)就越多,相對IP和TCP首部有更高的網(wǎng)絡(luò)利用率。則MSS的默認(rèn)值是536字節(jié)長(這個默認(rèn)值允許20字節(jié)的IP首部和20字節(jié)的TCP首部以適合576字節(jié)IP數(shù)據(jù)報)
本示例中:MSS為16344

9.2 其他選項:
- 窗口擴大選項(Windows Scaling):是為了擴大窗口。我們知道,TCP首部中窗口字段長度是16位,因此最大的窗口大小為64K字節(jié)。雖然這對早期的網(wǎng)絡(luò)是足夠用的,但對于包含衛(wèi)星信道的網(wǎng)絡(luò),傳播時延和寬帶都很大,要獲得高吞吐量需要更大的窗口大小。
(1)窗口擴大選項占3字節(jié),其中第一字節(jié)代表類型,第二字節(jié)代表長度,第三字節(jié)(shift count)則是擴展移位值S了,新的窗口值等于TCP首部中的窗口位數(shù)從16增大到(16+S)。移位值允許使用的最大值是14,相當(dāng)于窗口最大值增大到2(16+14)-1=230-1。
(2)窗口擴大選項可以在雙方初始建立TCP連接時進(jìn)行協(xié)商。如果連接的某一端實現(xiàn)了窗口擴大,當(dāng)它不再需要擴大其窗口時,可發(fā)送S=0選項,使窗口大小回到16。
本示例中:窗口擴大選項則是移位6,等于擴展了64倍(65565 * 2^6)

- 時間戳選項(Timestamps):占10字節(jié),其中最主要的字段是時間戳字段(4字節(jié))和時間戳回送回答字段(4字節(jié))。時間戳選項有以下兩個概念:
(1)用來計算往返時間RTT(往返時間)。發(fā)送方在發(fā)送報文段時把當(dāng)前時鐘的時間值放入時間戳字段,接收方在確認(rèn)該報文段時把時間戳字段復(fù)制到時間戳回送回答字段。因此,發(fā)送方在收到確認(rèn)報文后,可以準(zhǔn)確地計算出RTT來。為了減少任一端所維持的狀態(tài)數(shù)量,對于每個連接只保持一個時間戳的數(shù)值。選擇何時,更新這個數(shù)值的算法非常簡單(《TCP/IP詳解》):
1 ) T C P 跟蹤下一個 A C K 中將要發(fā)送的時間戳的值(一個名為 t s re c e n t 的 變 量 ) 以 及 最 后 發(fā) 送的 A C K 中的確認(rèn)序號(一個名為 l a s t a c k的變量)。這個序號就是接收方期望的序號。
當(dāng)一個包含有字節(jié)號 l a s t a c k的報文段到達(dá)時,則該報文段中的時間戳被保存在 t s re c e n t 中。
無論何時發(fā)送一個時間戳選項, t s re c e n t就 作 為 時 間 戳 回 顯 應(yīng) 答 字 段 被 發(fā) 送 , 而 序 號 字 段被保存在 l a s t a c k 中。 (2)用于處理防止序號繞回PAWS(TCP序號超過232的情況):TCP報文段的序號只有32位,而每增加232個序號就會重復(fù)使用原來用過的序號。當(dāng)使用高速網(wǎng)絡(luò)時,在一次TCP連接的數(shù)據(jù)傳送中序號很可能被重復(fù)使用。為了使接收方能夠把新的報文段和遲到很久的報文段區(qū)分開,則可以在報文段中加上這種時間戳。
本示例中: 發(fā)送的3588061560,因為是第一個SYN所以回復(fù)的是0

- NOP(NO-Operation):它要求選項部分中的每種選項長度必須是4字節(jié)的倍數(shù),不足的則用NOP填充。同時也可以用來分割不同的選項字段。如窗口擴大選項和SACK之間用NOP隔開
至此,一個SYN包就解析完了,對于PSH、ACK解析類似哦