在TCP/IP分層中,數據鏈路層用MTU(Maximum Transmission Unit,最大傳輸單元)來限制所能傳輸的數據包大小,MTU是指一次傳送的數據最大長度,不包括數據鏈路層數據幀的幀頭,如以太網的MTU為1500字節,實際上數據幀的最大長度為1512字節,其中以太網數據幀的幀頭為12字節。
當發送的IP數據報的大小超過了MTU時,IP層就需要對數據進行分片,否則數據將無法發送成功。
IP分片的實現
IP分片發生在IP層,不僅源端主機會進行分片,中間的路由器也有可能分片,因為不同的網絡的MTU是不一樣的,如果傳輸路徑上的某個網絡的MTU比源端網絡的MTU要小,路由器就可能對IP數據報再次進行分片。而分片數據的重組只會發生在目的端的IP層。
在IP首部有4個字節是用於分片的,如下圖所示。前16位是IP數據報的標識,同一個數據報的各個分片的標識是一樣的,目的端會根據這個標識來判斷IP分片是否屬於同一個IP數據報。中間3位是標志位,其中有1位用來表示是否有更多的分片,如果是最后一個分片,該標志位為0,否則為1。后面13位表示分片在原始數據的偏移,這里的原始數據是IP層收到的傳輸的TCP或UDP數據,不包含IP首部。
需要注意的,在分片的數據中,傳輸層的首部只會出現在第一個分片中,如下圖所示。因為傳輸層的數據格式對IP層是透明的,傳輸層的首部只有在傳輸層才會有它的作用,IP層不知道也不需要保證在每個分片中都有傳輸層首部。所以,在網絡上傳輸的數據包是有可能沒有傳輸層首部的。
避免IP分片
在網絡編程中,我們要避免出現IP分片,那么為什么要避免呢?原因是IP層是沒有超時重傳機制的,如果IP層對一個數據包進行了分片,只要有一個分片丟失了,只能依賴於傳輸層進行重傳,結果是所有的分片都要重傳一遍,這個代價有點大。由此可見,IP分片會大大降低傳輸層傳送數據的成功率,所以我們要避免IP分片。
對於UDP包,我們需要在應用層去限制每個包的大小,一般不要超過1472字節,即以太網MTU(1500)—UDP首部(8)—IP首部(20)。
對於TCP數據,應用層就不需要考慮這個問題了,因為傳輸層已經幫我們做了。在建立連接的三次握手的過程中,連接雙方會相互通告MSS(Maximum Segment Size,最大報文段長度),MSS一般是MTU—IP首部(20)—TCP首部(20),每次發送的TCP數據都不會超過雙方MSS的最小值,所以就保證了IP數據報不會超過MTU,避免了IP分片。
IP分片實例
1. UDP
從10.224.142.166向10.137.133.101發送3000字節的UDP數據,抓包的結果如下圖。從圖中可以看到這個UDP數據包被分成了3個IP片,從各分片的偏移量可以看出,3片包含的UDP數據大小分別是1480、1480、48(加上UDP首部8個字節),各分片加上IP首部的大小分別就是1500、1500、68,傳送的總的UDP數據大小為3008,由此也看出只有一個分片包含UDP首部。
2. TCP
從10.224.142.166向10.137.133.101發送2000字節的TCP數據,抓包的結果如下圖。從圖中可以看出TCP數據被分成了2個IP片,包含的數據大小分別為1448、552,從三次握手可以看出雙方通告的MSS都是1460字節,剛好是MTU(1500)—IP首部(20)—TCP首部(20),但實際為什么第一個分片只發送了1448字節呢,個人覺得應該是TCP首部還有一些選項占用了12個字節,也請知道的達人解釋一下。