tcp粘包和拆包的處理方案

tcp粘包和拆包的處理方案

 

 

 

產生tcp粘包和拆包的原因

 

我們知道tcp是以流動的方式傳輸數據,傳輸的最小單位爲一個報文段(segment)。tcp Header中有個Options標識位,常見的標識爲mss(Maximum Segment Size最大消息長度)指的是,連接層每次傳輸的數據有個最大限制MTU(Maximum Transmission Unit),一般是1500比特,超過這個量要分成多個報文段,mss則是這個最大限制減去TCP的header,光是要傳輸的數據的大小,一般爲1460比特。換算成字節,也就是180多字節。

 

MSS = MTU - header 

 

tcp爲提高性能,發送端會將需要發送的數據發送到緩衝區,等待緩衝區滿了之後,再將緩衝中的數據發送到接收方。同理,接收方也有緩衝區這樣的機制,來接收數據

 

發生TCP粘包、拆包主要是由於下面一些原因:

應用程序寫入的數據大於套接字緩衝區大小,這將會發生拆包

應用程序寫入數據小於套接字緩衝區大小,網卡將應用多次寫入的數據發送到網絡上,這將會發生粘包。

進行mss(最大報文長度)大小的TCP分段,當TCP報文長度-TCP頭部長度>mss的時候將發生拆包。

接收方法不及時讀取套接字緩衝區數據,這將發生粘包。

……

 

如何解決拆包粘包

 

既然知道了tcp是無界的數據流,且協議本身無法避免粘包,拆包的發生,那我們只能在應用層數據協議上,加以控制。通常在制定傳輸數據時,可以使用如下方法:

 

1、使用帶消息頭的協議消息頭存儲消息開始標識及消息長度信息,服務端獲取消息頭的時候解析出消息長度,然後向後讀取該長度的內容。

2、設置定長消息,服務端每次讀取既定長度的內容作爲一條完整消息。

 

3、設置消息邊界,服務端從網絡流中按消息編輯分離出消息內容。

 

=====================================================================

問題:

TCP是以段爲單位進行數據包的發送的。

(1)在建立TCP連接的同時,也可以確定發送數據包的單位,稱之爲“最大消息長度”:MSS。最理想的情況是,最大消息長度MSS正好是IP層中不被分片處理的最大數據長度。

(2)TCP在傳送大量數據的時候,是以“段=MSS的大小”將數據進行分割發送的,進行重發時也是以MSS爲單位的。

(3)最大消息長度——MSS是在三次握手的時候,在兩端主機之間被計算得出的。兩端主機在發出“建立TCP連接請求的SYN包”時,會在SYN包的TCP首部中寫入MSS選項,告訴對方自己所能夠適應的MSS的大小,然後發送端主機會在兩者之間選擇一個較小的MSS值投入使用。

 

 

TCP爲什麼引入接受緩存這個數據結構?

如果沒有接受緩存的話,或者說只有一個緩存的話,爲了保證接受的數據是按順序傳輸的,所以如果位於x序號之後的序號分組先到達目的主機的運輸層的話必然丟棄,這樣的話將在重傳上花費很大的開銷,所以一般如果有過大的序號達到接收端,那麼會按照序號緩存起來等待之前的序號分許到達,然後一併交付到應用進程。

 

TCP 粘包/拆包的原因及解決方法

TCP是以流的方式來處理數據,一個完整的包可能會被TCP拆分成多個包進行發送也可能把小的封裝成一個大的數據包發送。

 

TCP粘包/分包的原因:

應用程序寫入的字節大小大於套接字發送緩衝區的大小,會發生拆包現象,而應用程序寫入數據小於套接字緩衝區大小,網卡將應用多次寫入的數據發送到網絡上,這將會發生粘包現象;

進行MSS大小的TCP分段,當TCP報文長度-TCP頭部長度>MSS的時候將發生拆包

以太網幀的payload(淨荷)大於MTU(1500字節)進行ip分片。

 

解決方法

消息定長:FixedLengthFrameDecoder類

包尾增加特殊字符分割:行分隔符類:LineBasedFrameDecoder或自定義分隔符類 :DelimiterBasedFrameDecoder

將消息分爲消息頭和消息體:LengthFieldBasedFrameDecoder類。分爲有頭部的拆包與粘包、長度字段在前且有頭部的拆包與粘包、多擴展頭部的拆包與粘包。

 

 

發佈了701 篇原創文章 · 獲贊 67 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章