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