爲什麼TCP/IP包長會大於MTU? 原

前戲

當你看到這個標題第一眼到你看到這篇文章的內容期間,你心裏也許會想,特麼在逗我呢吧?TCP/IP包怎麼可能會大於MTU?難道書上都是騙人的?確實在tcp/ip第一卷裏面描述IP協議分片一節裏面講到,當IP包大於MTU時,會對包進行分片。既然會分片,那麼這個包大於MTU是幾個意思?且聽我慢慢道來。

什麼是MTU

MTU(Maximum Transmission Unit),即最大傳輸單元,意思是在網絡通信協議裏規定最大傳輸的字節數量,通常是1500字節(不同網絡大小不一樣,可使用ifconfig查看),最小是46。

起因

首先事情的起因是因爲跟前端調數據,前端老吼沒收到數據,我說發了,他說沒收到,我說發了........雙方難分勝負,唯有抓包,方能一決雌雄。說時遲那時快,抄起tcpdump就開幹,然後在抓包過程中,偶爾有那麼幾個包居然比MTU還長,我當時就納了悶了,說好的IP包分片呢?人與機器最基本的信任都沒有了,我還打個卵的碼啊。於是翻了一些資料,終於知道這個分片不是發生在IP協議上,而是在TCP協議上(其實主要還是不熟悉tcpdump,因爲如果有tcp分片,seq格式就是當前seq:下一個seq,並且連續幾個包的ack都一樣)。包內容如下:


結果

雖然現在已經知道是tcp分片而非ip分片,但是包的大小還是超出了MTU,於是又一輪google,原來有個東西叫tso(tcp segment offload),意思是如果網卡支持tso,操作系統發送大的tcp包時,不需要消耗CPU來計算分片,而是將整個包發送到網卡,由網卡的NPU來進行分片處理,這樣還能減少TCP頭的傳輸次數(一個64K的數據包,需要45個分片,那麼將多傳輸1760字節(40x44)的tcp頭)。

查看你網卡是否支持tso,請使用如下命令:

ethtool --show-offload eth0

這時候我們來禁用一下tso,只需要執行如下命令

ethtool -K eth0 tso off

再來一輪tcpdump測試,發現數據包終於正常了,不再會大於MTU了。


其實無論服務器發送的包多大,反正最終都會被分片,可能是操作系統,可能是網卡,因此客戶端收到的包都是小於MTU的。


分片

爲什麼ip有分片了,tcp還要再搞一個分片呢?因爲ip層不保證數據成功送達,並且ip層分片可能發生在源主機,也可能在路由器上,一旦有分片丟失,將會造成整個ip包重傳(其實這個重傳是tcp層發起的,因爲目標機器沒有收到完整的ip包,也不會有ack,那麼源機器在一定時間內就會發起重傳,導致整個tcp包又被傳了一次),因此就有了tcp分片,當一片數據丟失,只需要重傳丟失的那一片即可。


結論

tcpdump抓包的數據是在包送到網卡之前的信息,所以在tcpdump裏面的包大小可能會大於MTU,但是一旦數據進入網卡後的處理信息在tcpdump裏面是反應不了的,因此數據包被分片這樣的消息自然是沒辦法知道,只有在目標方纔能反應出具體的分包細節。所以這次發現tcp/ip包長大於MTU其實算是個“假象”,因爲在真正的鏈路層上傳輸數據時是不會大於MTU的。


參考資料

https://en.wikipedia.org/wiki/Large_segment_offload

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章