網絡中出現TCP、UDP粘包、分包的兩點解決辦法

粘包產生原因:
先說TCP:由於TCP協議本身的機制(面向連接的可靠地協議-三次握手機制)客戶端與服務器會維持一個連接(Channel),數據在連接不斷開的情況下,可以持續不斷地將多個數據包發往服務器,但是如果發送的網絡數據包太小,那麼他本身會啓用Nagle算法(可配置是否啓用)對較小的數據包進行合併(基於此,TCP的網絡延遲要UDP的高些)然後再發送(超時或者包大小足夠)。那麼這樣的話,服務器在接收到消息(數據流)的時候就無法區分哪些數據包是客戶端自己分開發送的,這樣產生了粘包;服務器在接收到數據庫後,放到緩衝區中,如果消息沒有被及時從緩存區取走,下次在取數據的時候可能就會出現一次取出多個數據包的情況,造成粘包現象(確切來講,對於基於TCP協議的應用,不應用包來描述,而應 用 流來描述),個人認爲服務器接收端產生的粘包應該與linux內核處理socket的方式 select輪詢機制的線性掃描頻度無關。
再說UDP:本身作爲無連接的不可靠的傳輸協議(適合頻繁發送較小的數據包),他不會對數據包進行合併發送(也就沒有Nagle算法之說了),他直接是一端發送什麼數據,直接就發出去了,既然他不會對數據合併,每一個數據包都是完整的(數據+UDP頭+IP頭等等發一次數據封裝一次)也就沒有粘包一說了。

分包產生的原因就簡單的多:可能是IP分片傳輸導致的,也可能是傳輸過程中丟失部分包導致出現的半包,還有可能就是一個包可能被分成了兩次傳輸,在取數據的時候,先取到了一部分(還可能與接收的緩衝區大小有關係),總之就是一個數據包被分成了多次接收。

解決辦法:

粘包與分包的處理方法:

我根據現有的一些開源資料做了如下總結(常用的解決方案):
一個是採用分隔符的方式,即我們在封裝要傳輸的數據包的時候,採用固定的符號作爲結尾符(數據中不能含結尾符),這樣我們接收到數據後,如果出現結尾標識,即人爲的將粘包分開,如果一個包中沒有出現結尾符,認爲出現了分包,則等待下個包中出現後 組合成一個完整的數據包,這種方式適合於文本傳輸的數據,如採用/r/n之類的分隔符;

另一種是採用在數據包中添加長度的方式,即在數據包中的固定位置封裝數據包的長度信息(或可計算數據包總長度的信息),服務器接收到數據後,先是解析包長度,然後根據包長度截取數據包(此種方式常出現於自定義協議中),但是有個小問題就是如果客戶端第一個數據包數據長度封裝的有錯誤,那麼很可能就會導致後面接收到的所有數據包都解析出錯(由於TCP建立連接後流式傳輸機制),只有客戶端關閉連接後重新打開纔可以消除此問題,我在處理這個問題的時候對數據長度做了校驗,會適時的對接收到的有問題的包進行人爲的丟棄處理(客戶端有自動重發機制,故而在應用層不會導致數據的不完整性);

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