在編寫網(wǎng)絡(luò)程序時(shí),常使用TCP協(xié)議。那么一個(gè)tcp包到底由哪些東西構(gòu)成的呢?其實(shí)一個(gè)TCP包,首先需要通過IP協(xié)議承載,而IP報(bào)文,又需要通過以太網(wǎng)傳送。下面我們來看看幾種協(xié)議頭的構(gòu)成 一 .Ethernet頭 以太幀分好幾種類型,常見的以太幀為Ethernet II 下面就是一個(gè)典型的Ethernet II幀 Ethernet II類型以太網(wǎng)幀的最小長度為64字節(jié)(6+6+2+46+4),最大長度為1518字節(jié)(6+6+2+1500+4) 首先是目的MAC 6個(gè)字節(jié),然后源MAC6個(gè)字節(jié),接下來數(shù)據(jù)類型兩個(gè)字節(jié)。 常見的類型如下 IPv4: 0x0800 ARP:0x0806 PPPoE:0x8864 802.1Q tag: 0x8100 IPV6: 0x86DD MPLS Label:0x8847 然后是數(shù)據(jù)長度,46-1500字節(jié)。對(duì)于不定長的數(shù)據(jù)包,幀最后還有4個(gè)字節(jié)的FCS(Frame check sequence) 下面是一個(gè)以太幀頭示例,該報(bào)文類型為IPv4(0x8000) 二 IP頭部 對(duì)于一個(gè)IPv4類型的以太幀,數(shù)據(jù)的開始就是IP頭部。一般IPv4的頭部是20個(gè)字節(jié)。 版本號(hào)(Version):4bit。表明IP協(xié)議的版本號(hào)。一般為0100(IPv4),0110(IPv6) IP包頭長度(Header Length):4bit。用于描述IP包頭長度,因?yàn)镮P包頭長度是可變的。 這里所指示的長度,是以4個(gè)字節(jié)為一個(gè)單位。例如,一個(gè)IP包頭的長度最長為“1111”,即15*4=60個(gè)字節(jié)。IP包頭最小長度為20字節(jié)。 服務(wù)類型(Type of Service):長度8比特。 標(biāo)記(Flags):3bit。第一位是保留位不使用。第二位是DF(Don't
Fragment)位,DF位設(shè)為1時(shí)表明路由器不能對(duì)該數(shù)據(jù)包分包。如果一個(gè)數(shù)據(jù)包無法在不分段的情況下發(fā)送,則路由器會(huì)丟棄該數(shù)據(jù)包并返回一個(gè)錯(cuò)誤信息。第三位是MF(More Fragments)位,當(dāng)路由器對(duì)一個(gè)上層數(shù)據(jù)包分段,則路由器會(huì)在除了最后一個(gè)分段的IP包的包頭中將MF位設(shè)為1。 片偏移(Fragment Offset):13bit。表示該IP包在該組分片包中位置,接收端靠此來組裝還原IP包。 生存時(shí)間(TTL):8bit。當(dāng)IP包在網(wǎng)絡(luò)上傳送時(shí),每經(jīng)過一個(gè)路由器,TTL就自動(dòng)減一。值為0時(shí),則丟棄報(bào)文。防止報(bào)文進(jìn)入環(huán)路 協(xié)議(Protocol):8bit。標(biāo)識(shí)IP頭后面的報(bào)文協(xié)議類型 1 ICMP 2 IGMP 6 TCP 17 UDP 88 IGRP 89 OSPF 頭校驗(yàn)和(Header Checksum):16bit。用來做IP頭部的正確性檢測,但不包含數(shù)據(jù)部分。由于路由器會(huì)改變TTL,所以路由器會(huì)為每個(gè)通過的數(shù)據(jù)包重新計(jì)算這個(gè)值。 源和目的地址(Source and Destination Addresses):這兩個(gè)地段都是32比特。標(biāo)識(shí)了這個(gè)IP包的起源和目標(biāo)地址。要注意除非使用NAT,否則整個(gè)傳輸?shù)倪^程中,這兩個(gè)地址不會(huì)改變。 下圖就是一個(gè)IP頭的內(nèi)容 三 TCP 頭部 TCP封裝在IP報(bào)文中的時(shí)候,如下圖所示,TCP頭緊接著IP頭(IPV6有擴(kuò)展頭的時(shí)候,則TCP頭在擴(kuò)展頭后面),不攜帶選項(xiàng)(option)的TCP頭長為20bytes,攜帶選項(xiàng)的TCP頭最長可到60bytes。 源端口(Source Port):16bit, 表示報(bào)文發(fā)送方的端口號(hào) 目的端口(Destination port): 16bit,表示報(bào)文接收方的端口號(hào) 序列號(hào)(SN):32bit,標(biāo)識(shí)了TCP報(bào)文中第一個(gè)byte在對(duì)應(yīng)方向的傳輸中對(duì)應(yīng)的字節(jié)序號(hào)。當(dāng)SYN出現(xiàn),序列碼實(shí)際上是初始序列碼(ISN),而第一個(gè)數(shù)據(jù)字節(jié)是ISN 1,單位是byte。比如發(fā)送端發(fā)送的一個(gè)TCP包凈荷(不包含TCP頭)為12byte,SN為5,則發(fā)送端接著發(fā)送的下一個(gè)數(shù)據(jù)包的時(shí)候,SN應(yīng)該設(shè)置為5 12=17。通過系列號(hào),TCP接收端可以識(shí)別出重復(fù)接收到的TCP包,從而丟棄重復(fù)包,同時(shí)對(duì)于亂序數(shù)據(jù)包也可以依靠系列號(hào)進(jìn)行重排序,進(jìn)而對(duì)高層提供有序的數(shù)據(jù)流。另外SYN標(biāo)志和FIN標(biāo)志在邏輯上也占用一個(gè)byte,當(dāng)SYN標(biāo)志位有效的時(shí)候,該字段也稱為ISN(initial sequence number),詳細(xì)請(qǐng)參考后續(xù)的TCP連接管理。 應(yīng)答號(hào)(ACK):32bit,標(biāo)識(shí)了報(bào)文發(fā)送端期望接收的字節(jié)序列。如果設(shè)置了ACK控制位,這個(gè)值表示一個(gè)準(zhǔn)備接收的包的序列碼,注意是準(zhǔn)備接收的包,比如當(dāng)前接收端接收到一個(gè)凈荷為12byte的數(shù)據(jù)包,SN為5,則發(fā)送端可能會(huì)回復(fù)一個(gè)確認(rèn)收到的數(shù)據(jù)包,如果這個(gè)數(shù)據(jù)包之前的數(shù)據(jù)也都已經(jīng)收到了,這個(gè)數(shù)據(jù)包中的ACK Number則設(shè)置為12 5=17,表示17byte之前的數(shù)據(jù)都已經(jīng)收到了。在舉一個(gè)例子,如果在這個(gè)數(shù)據(jù)包之前有個(gè)SN為3,凈荷為2byte的數(shù)據(jù)包丟失,則在接受端接收到這個(gè)SN為5的亂序數(shù)據(jù)包的時(shí)候,協(xié)議要求接收端必須要回復(fù)一個(gè)ACK確認(rèn)包,這個(gè)確認(rèn)包中的Ack Number只能設(shè)置為3。 頭長(Header Length):4bit,指示TCP頭的長度,即數(shù)據(jù)從何處開始。最大為15,單位是32比特,即4個(gè)字節(jié),與IP頭中的長度定義相同。 保留(Reserved):4bit,這些位必須是0。為了將來定義新的用途所保留,其中RFC3540將Reserved字段中的最后一位定義為Nonce標(biāo)志。 標(biāo)志(Code Bits):8bit CWR(Congestion Window Reduce):擁塞窗口減少標(biāo)志被發(fā)送主機(jī)設(shè)置,用來表明它接收到了設(shè)置ECE標(biāo)志的TCP包,發(fā)送端將通過降低發(fā)送窗口的大小來降低發(fā)送速率 ECE(ECN Echo):ECN響應(yīng)標(biāo)志被用來在TCP3次握手時(shí)表明一個(gè)TCP端是否具備ECN功能,并且表明接收到的TCP包的IP頭部的ECN被設(shè)置為11。更多信息請(qǐng)參考RFC793。 URG(Urgent):表示緊急(The urgent pointer) 指針是否有效。 ACK(Acknowledgment):1表示這是一個(gè)確認(rèn)的TCP包, 0則不是確認(rèn)包。 PSH(Push):該標(biāo)志置位時(shí),一般是表示發(fā)送端緩存中已經(jīng)沒有待發(fā)送的數(shù)據(jù),接收端不將該數(shù)據(jù)進(jìn)行隊(duì)列處理,而是盡可能快將數(shù)據(jù)轉(zhuǎn)由應(yīng)用處理。 RST(Reset):用于復(fù)位相應(yīng)的TCP連接。通常在發(fā)生異常或者錯(cuò)誤的時(shí)候會(huì)觸發(fā)復(fù)位TCP連接。 SYN(Synchronize):表示同步序列編號(hào)(Synchronize Sequence Numbers)是否有效。該標(biāo)志僅在三次握手建立TCP連接時(shí)有效。它提示TCP連接的服務(wù)端檢查序列編號(hào),該序列編號(hào)為TCP連接發(fā)起端(一般是客戶端)的初始序列編號(hào)。在這里,可以把TCP序列編號(hào)看作是一個(gè)范圍從0到4,294,967,295的32位計(jì)數(shù)器。通過TCP連接交換的數(shù)據(jù)中每一個(gè)字節(jié)都經(jīng)過序列編號(hào)。在TCP報(bào)頭中的序列編號(hào)欄包括了TCP分段中第一個(gè)字節(jié)的序列編號(hào)。 FIN(Finish):帶有該標(biāo)志置位的數(shù)據(jù)包用來結(jié)束一個(gè)TCP會(huì)話,但對(duì)應(yīng)端口仍處于開放狀態(tài),準(zhǔn)備接收后續(xù)數(shù)據(jù)。當(dāng)FIN標(biāo)志有效的時(shí)候我們稱呼這個(gè)包為FIN包。 窗口大小(Window Size):16bit,表示從Ack Number開始還能接收多少字節(jié)的數(shù)據(jù)量,即當(dāng)前接收端的接收窗口還有多少剩余空間。用于TCP的流量控制。 校驗(yàn)和(Checksum):16bit。發(fā)送端基于數(shù)據(jù)內(nèi)容計(jì)算一個(gè)數(shù)值,接收端要與發(fā)送端數(shù)值結(jié)果完全一樣,才能證明數(shù)據(jù)的有效性。接收端checksum校驗(yàn)失敗的時(shí)候會(huì)直接丟掉這個(gè)數(shù)據(jù)包。CheckSum是根據(jù)偽頭 TCP頭 TCP數(shù)據(jù)三部分進(jìn)行計(jì)算的。 緊急指針(Urgent Pointer):16位,在URG標(biāo)志設(shè)置了時(shí)才有效。與序號(hào)字段的值相加后表示最后一個(gè)緊急數(shù)據(jù)的下一字節(jié)的序號(hào),可以說這個(gè)字段是緊急指針相對(duì)當(dāng)前序號(hào)的偏移。 選項(xiàng)(Option):長度不定,但長度必須以是32bits的整數(shù)倍。常見的選項(xiàng)包括MSS、SACK、Timestamp等等,后續(xù)的內(nèi)容會(huì)分別介紹相關(guān)選項(xiàng)。 一個(gè)完整的TCP頭展示 |
|