网络协议包格式
網上找到了一張數據幀表示圖
?在linux系統中,使用struct ethhdr結構體來表示以太網幀的頭部。這個struct ethhdr結構體位于#include<linux/if_ether.h>之中。
#define ETH_ALEN 6 //定義了以太網接口的MAC地址的長度為6個字節
#define ETH_HLAN 14 //定義了以太網幀的頭長度為14個字節
#define ETH_ZLEN 60 //定義了以太網幀的最小長度為 ETH_ZLEN + ETH_FCS_LEN = 64個字節
#define ETH_DATA_LEN 1500 // 定義了以太網幀的最大負載為1500個字節
#define ETH_FRAME_LEN 1514 // ETH_HLAN + ETH_DATA_LEN
#define ETH_FCS_LEN 4 //定義了以太網幀的CRC值占4個字節
以太網幀的最短長度為64字節,或者幀中的數據不得少于46個字節,其中以太網幀頭有18字節
ETH_ALEN * 2 + 2字節類型 = 18字節
注意如果是802.3的規范,它支持SNAP和802.3以太,其中的2個字節的類型字段就變為幀的長度,小于以上長度的幀或數據需要在幀中加入“填充數據(pad)” 。
以太網幀的最長長度為1518字節。我們所說的MTU 以太網一般為1500,加上以太網幀頭18字節。
ETH_HLAN + ETH_DATA_LEN + ETH_FCS_LEN = 1518字節
注意,802.3規范已經把最大長度改為1536(0x0600)了。
struct ethhdr {unsigned char h_dest[ETH_ALEN]; //目的MAC地址unsigned char h_source[ETH_ALEN]; //源MAC地址__u16 h_proto ; //網絡層所使用的協議類型 } __attribute__((packed)) //用于告訴編譯器不要對這個結構體中的縫隙部分進行填充操作;#define? ETH_P_IP 0x0800 //IP協議
#define? ETH_P_ARP 0x0806? //地址解析協議(Address Resolution Protocol)
#define? ETH_P_RARP 0x8035? //返向地址解析協議(Reverse Address Resolution Protocol)
#define? ETH_P_IPV6 0x86DD? //IPV6協議
struct iphdr {#if defined(__LITTLE_ENDIAN_BITFIELD)__u8 ihl:4,version:4;#elif defined (__BIG_ENDIAN_BITFIELD)__u8 version:4,ihl:4;#else#error "Please fix <asm/byteorder.h>"#endif__u8 tos;__be16 tot_len;__be16 id;__be16 frag_off;__u8 ttl;__u8 protocol;__sum16 check;__be32 saddr;__be32 daddr;/*The options start here. */?};iphdr->version
版本(4位),目前的協議版本號位4,也稱之為IPv4
iphdr->ihl
首部長度(4位),首部長度是指IP層頭部占32bit字的數目,也就是IP層頭部包含多少個4字節(32b),包括任何選項,由于它是一個4bit(最大表示15)字段,因此首部最長為15 *4 = 60個字節。普通IP數據報字段的值為5 ==》5*32/8=20Bytes
iphdr->tos
服務類型字段(8位):服務類型(TOS)字段包括一個3bit的優先權字段(已被忽略),4bit的TOS子字段和1bit未用位但必須置0。4bit的TOS子字段分別表示最小時延、最大吞吐量、最高可靠性和最小費用。4bit中只能設置1bit。如果4bit均為0表示這是一般服務。
iphdr->tot_len
總長度字段(16)位指的是整個IP數據包的長度(首部+數據部分),以字節為單位。利用首部長度字段和總長度字段,就可以知道IP數據報中數據內容的起始位置和長度。由于該字段長16bit,所以IP數據包最長可長達65535字節。
總長度字段是IP首部中必要的內容,因為一些數據鏈路(如以太網)需要填充一些數據以達到最小長度。盡管以太網的最小幀長為46字節,但IP數據可能更短。如果沒有總長度字段,那么IP層就不知道46字節中有多少是IP數據報的內容。
iphdr->id
標識字段(16bit)唯一地標識主機發送地每一份數據報,通常每發送一份報文他的值就加1。
iphdr->frag_off
frag_off低13位
標識分段偏移(Fragment offset)域指明了該分段在當前數據報中的什么位置上。除了一個數據報的最后一個分段以外,其他所有的分段(分片)必須是8字節的倍數。這是8字節是基本分段單位。由于該域有13個位,所以每個數據報最多有8192個分段。因此最大數據報長度為65536字節,比iphdr->tot_len域還大1。
frag_off高3位:
l? 比特0保留,必須為0;
l? 比特1是“更多分片”(MF—More Fragment)標志。除了最后一片外,其他每個組成數據報的片都要把該比特置1.
l? 比特2是“部分片”(DF—Don’t Fragment)標志,如果將這一比特置1,IP將不對數據報進行分片,這是如果需要進行分片的數據報到來,會丟棄此數據報并發送一個ICMP差錯報文給起始端。
iphdr->ttl
TTL(Time to live)8位,生存時間字段設置了數據報可以經過的最多路由器數。它指定了數據報的生存時間。TTl的初始值由源主機設置(通常為32或64),一旦經過一個處理它的路由器,它的值就減去1。當該字段值為0時,數據報就被丟棄,并發送ICMP報文通知源主機。
TTL(Time to live)域是一個用于限制分組生存期的計數器。這里的計數單位為秒,因此最大生存期為255s。在每一跳上該計數器必須被遞減。而且數據報在一臺路由器上排隊時間較長時,該計數器必須被多倍遞減。在實踐中,當它遞減到0時,分組會被丟棄,路由器給源主機發送一個警告分組。此項特性可以避免數據報長時間地逗留在網絡中。
iphdr->protocol
協議字段(8位):根據它可以識別是哪個協議向IP傳送數據。
當網絡層組裝完成一個完整地數據報之后,他需要知道該如何對它進行處理。協議(Protocol)域指明了該將它交給哪個傳輸進程。TCP或者UDP或者其他協議。
iphdr->check
首部校驗和字段(16)位時根據IP首部計算的校驗和碼。他不對首部后面的數據進行計算。ICMP、IGMP、UDP、TCP在它們各自的首部中均含有同時覆蓋首部和數據校驗和碼。
為了計算一份數據報的IP校驗和,首先把校驗和字段置為0。然后對首部中每個16bit進行二進制反碼求和(整個首部看出時一串16bie的字組成),結果存在校驗和字段中。當收到一份IP數據報后,同樣對首部中的每個16bit進行二進制反碼求和。由于接收方在計算過程中包含了發送方存在首部中的校驗和,因此如果首部在傳輸過程中沒有發生任何差錯,那么接收方計算的結果應該全為1。否則就意味著數據在傳輸過程中發生錯誤,IP就會丟棄收到的數據報。但是不生成差錯報文,由上層區發現丟失的數據報并進行重傳。
iphdr->saddr
32源IP地址
iphdr->daddr
32位目的IP地址
總結
- 上一篇: win10双机互联
- 下一篇: 无线宝服务器,体验 | 闲置带宽换京豆,