??????? 在使用 TCP 協議的網絡程序中,用戶數據從產生到從網卡發出去一般要經過如下的逐層封裝過程:
??????? 從下往上看:
??????? 1)鏈路層通過加固定長度的首部、尾部來封裝 IP 數據報(Datagram) 產生以太網幀(Frame)。 其中首部存在對封裝數據的標識:是 IP(0x0800,例如本例) 、ARP(0x0806) 還是 RARP(0x0835)。
??????? 2)網絡層通過加 IP首部來封裝 TCP 段(Segment) 產生 IP 數據報。 其中首部存在對封裝數據的標識:是 ICMP(0x01)、IGMP(0x02)、TCP(0x06,例如本例)還是 UDP(0x11)。
??????? 3)傳輸層通過加首部來封裝應用數據產生 TCP 段。其中TCP首部存在對封裝數據的標識:端口號,來標識是那個應用程序產生的數據。
??????? 4)按這種處理邏輯,在應用層,對于我們要處理的應用數據理所當然的加上固定長度的首部,首部中同樣含有某些標識,標識些什么呢?按經驗,一般會標識本次數據的業務意義,在程序中一般處理為業務集合(枚舉型)的某個元素;如果是 TCP應用(本例) 還可能包括應用數據總體長度。
Ethernet、Tcp、Udp 等協議的數據包格式
??????? TCP/IP協議是一個比較復雜的協議集,有很多專業書籍介紹。在此,我僅介紹其與編程密切相關的部分:以太網上 TCP/IP 協議的分層結構及其報文格式。我們知道TCP/IP 協議采用分層結構,其分層模型及協議如下表:
??????? 協議采用分層結構,因此,數據報文也采用分層封裝的方法。下面以應用最廣泛的以太網為例說明其數據報文分層封裝,如下圖所示:
??????? 任何通訊協議都有獨特的報文格式,TCP/IP 協議也不例外。對于通訊協議編程,我們首先要清楚其報文格式。由于TCP/IP 協議采用分層模型,各層都有專用的報頭,以下就簡單介紹以太網下 TCP/IP 各層報文格式。
??????? 8 字節的前導用于幀同步,CRC 域用于幀校驗。這些用戶不必關心其由網卡芯片自動添加。目的地址和源地址是指網卡的物理地址,即 MAC 地址,具有唯一性。幀類型或協議類型是指數據包的高級協議,如 0x0806 表示 ARP 協議,0x0800 表示 IP 協議等。之所以要把數據組合成以幀為單位傳送,是為了在出錯時,可只將有錯的幀重發,而不必將全部數據重新發送,從而提高了效率。注:數據以幀為單位進行發送,若某一幀有差錯,以后就重傳這個出錯的幀。一個幀要有幀界限,接收端在收到比特流后,能夠依據幀界限正確知道哪些比特構成一個幀。接收端找到幀定界符并確定幀的準確位置,就是完成了幀同步。
??????? IP 數據報頭格式如下圖:
???????版本號(Version):長度4比特。標識目前采用的IP協議的版本號。一般的值為0100(IPv4),0110(IPv6)
??????? IP包頭長度(Header Length):長度4比特。描述IP包頭的長度。因為在IP包頭中有變長的可選部分。該部分占4個bit位,單位為32bit(4個字節),即本區域值= IP頭部長度(單位為bit)/(8*4),因此,一個IP包頭的長度最長為“1111”,即15*4=60個字節。IP包頭最小長度為20字節。
??????? 服務類型(Type of Service):長度8比特。這八位被分成如下定義,其中PPP三位組合使用:PPP DTRC0
????????????? PPP:定義包的優先級,取值越大數據越重要
????????????? ? ? 000 普通 (Routine)
???????????? ? ?? 001 優先的 (Priority)
???????????? ? ?? 010 立即的發送 (Immediate)
???????? ? ? ? ?? 011 閃電式的 (Flash)
???????????? ? ?? 100 比閃電還閃電式的 (Flash Override)
???????????? ? ?? 101 CRI/TIC/ECP(找不到這個詞的翻譯)
???????????? ?? ? 110 網間控制 (Internetwork Control)
?????????? ? ?? ? 111 網絡控制 (Network Control)
????? ? ? ? ?? ??? D 時延: 0:普通 1:延遲盡量小
?????? ? ? ? ?? ??T 吞吐量: 0:普通 1:流量盡量大
???? ? ? ? ?? ????R 可靠性: 0:普通 1:可靠性盡量大
???? ? ? ? ?? ????M 傳輸成本: 0:普通 1:成本盡量小
????? ? ? ? ?? ???0 最后一位被保留,恒定為0
???????IP包總長(Total Length):長度16比特。 以字節為單位計算的IP包的長度 (包括頭部和數據),所以IP包最大長度65535字節。
??????? 標識符(Identifier):長度16比特。該字段和Flags和Fragment Offest字段聯合使用,對較大的上層數據包進行分段(fragment)操作。路由器將一個包拆分后,所有拆分開的小包被標記相同的值,以便目的端設備能夠區分哪個包屬于被拆分開的包的一部分。
??????? 標記(Flags):長度3比特。該字段第一位不使用。第二位是DF(Don't Fragment)位,DF位設為1時表明路由器不能對該上層數據包分段。如果一個上層數據包無法在不分段的情況下進行轉發,則路由器會丟棄該上層數據包并返回一個錯誤信息。第三位是MF(More Fragments)位,當路由器對一個上層數據包分段,則路由器會在除了最后一個分段的IP包的包頭中將MF位設為1。
??????? 片偏移(Fragment Offset):長度13比特。表示該IP包在該組分片包中位置,接收端靠此來組裝還原IP包。
??????? 生存時間(TTL):長度8比特。當IP包進行傳送時,先會對該字段賦予某個特定的值。當IP包經過每一個沿途的路由器的時候,每個沿途的路由器會將IP包的TTL值減少1。如果TTL減少為0,則該IP包會被丟棄。這個字段可以防止由于路由環路而導致IP包在網絡中不停被轉發。
??????? 協議(Protocol):長度8比特。標識了上層所使用的協議。
??????????????? 以下是比較常用的協議號:
? ? ? ? ? ? ? ? ? ? ? ? ? 1????ICMP
? ? ? ? ? ? ? ? ? ? ?? ?? 2????IGMP
? ? ? ? ? ? ? ? ? ? ?? ?? 6????TCP
? ? ? ? ? ? ? ? ? ? ? ? ? 17??? UDP
? ? ? ? ? ? ? ? ? ? ? ? ? 88??? IGRP
????????????????????????? 89??? OSPF
??????頭部校驗(Header Checksum):長度16位。用來做IP頭部的正確性檢測,但不包含數據部分。 因為每個路由器要改變TTL的值,所以路由器會為每個通過的數據包重新計算這個值。
?????? 起源和目標地址(Source and Destination Addresses):這兩個地段都是32比特。標識了這個IP包的起源和目標地址。要注意除非使用NAT,否則整個傳輸的過程中,這兩個地址不會改變。
?????? 至此,IP包頭基本的20字節已介紹完畢,此后部分屬于可選項,不是必須的部分。
????? 可選項(Options):這是一個可變長的字段。該字段屬于可選項,主要用于測試,由起源設備根據需要改寫。可選項目包含以下內容:
?? ?? 松散源路由(Loose source routing):給出一連串路由器接口的IP地址。IP包必須沿著這些IP地址傳送,但是允許在相繼的兩個IP地址之間跳過多個路由器。
? ? ? 嚴格源路由(Strict source routing):給出一連串路由器接口的IP地址。IP包必須沿著這些IP地址傳送,如果下一跳不在IP地址表中則表示發生錯誤。
?? ?? 路由記錄(Record route):當IP包離開每個路由器的時候記錄路由器的出站接口的IP地址。
? ? ? 時間戳(Timestamps):當IP包離開每個路由器的時候記錄時間。
?? ?? 填充(Padding):因為IP包頭長度(Header Length)部分的單位為32bit,所以IP包頭的長度必須為32bit的整數倍。因此,在可選項后面,IP協議會填充若干個0,以達到32bit的整數倍。
typedef struct _iphdr //定義IP首部
{
unsigned char h_lenver; //4位首部長度+4位IP版本號
unsigned char tos; //8位服務類型TOS
unsigned short total_len; //16位總長度(字節)
unsigned short ident; //16位標識
unsigned short frag_and_flags; //3位標志位
unsigned char ttl; //8位生存時間 TTL
unsigned char proto; //8位協議 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校驗和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IP_HEADER;
??????? 我們用單片機實現 TCP/IP 協議要作一些簡化,不考慮數據分片和優先權。因此,在此我們不討論服務類型和標志偏移域,只需填“0” 即可。協議“版本”為 4,“頭長度”單位為 32Bit,“總長度”以字節為單位,表示整個 IP 數據報長度。“標識”是數據包的 ID 號,用于識別不同的 IP 數據包。“生存時間” TTL 是個數量及的概念,防止無用數據包一直存在網絡中。一般每經過路由器時減一,因此通過 TTL 可以算出數據包到達目的地所經過的路由器個數。“協議”域表示創建該數據包的高級協議類型。如 1 表示 ICMP 協議,6 表示 TCP 協議,17 表示 UDP 協議等。IP 數據包為簡化數據轉發時間,僅采用頭校驗的方法,數據正確性由高層協議保證。
??????? ICMP(網間網控制報文協議)協議 ? ?? 應用廣泛。在此僅給出最常見的回應請求與應答報文格式, 用戶命令 ping 便是利用此報文來測試信宿機的可到達性。 報文格式如下圖所示:
?????? 類型 0 為回應應答報文,8 為回應請求報文。整個數據包均參與檢驗。注意 ICMP 封裝在 IP 數據包里傳送。
??????? TCP 是面向連接的可靠數據傳輸協議,因此比較復雜,在此僅作簡單介紹。“序號”指數據在發送端數據流中的位置。“確認號”指出本機希望下一個接收的字節的序號。與 IP 校驗不同的是 TCP,UDP 校驗采用偽頭標加整個報文一同校驗的方法。TCP 協議工作原理另行介紹。