socket通信中的粘包、拆包問題

 

在做一個socket通信的項目,需要對消息做驗證,判斷是否被篡改,採取了hash摘要,使用連發兩條的辦法,第一條發送hash摘要,第二條爲密文消息,接收到保存第一個hash值,解密後算出明文hash進行比較。過程中發生了粘包現象。

解決辦法:發送和接收hash的時候,因爲hash是定長的,所以設置緩衝區大小爲對應大小,即可完美拆包。


本文轉載自:https://my.oschina.net/u/3318187/blog/1635082

在平時客戶端socket開發中,如果客戶端連續不斷的向服務端發送數據包時,服務端接收的數據會出現兩個數據包粘在一起的情況,這就是TCP協議中經常會遇到的粘包以及拆包的問題。

我們都知道TCP屬於傳輸層的協議,傳輸層除了有TCP協議外還有UDP協議。那麼UDP是否會發生粘包或拆包的現象呢?答案是不會。UDP是基於報文發送的,從UDP的幀結構可以看出,在UDP首部採用了16bit來指示UDP數據報文的長度,因此在應用層能很好的將不同的數據報文區分開,從而避免粘包和拆包的問題。而TCP是基於字節流的,雖然應用層和TCP傳輸層之間的數據交互是大小不等的數據塊,但是TCP把這些數據塊僅僅看成一連串無結構的字節流,沒有邊界;另外從TCP的幀結構也可以看出,在TCP的首部沒有表示數據長度的字段,基於上面兩點,在使用TCP傳輸數據時,纔有粘包或者拆包現象發生的可能。

粘包、拆包表現形式

現在假設客戶端向服務端連續發送了兩個數據包,用packet1和packet2來表示,那麼服務端收到的數據可以分爲三種,現列舉如下:

第一種情況,接收端正常收到兩個數據包,即沒有發生拆包和粘包的現象,此種情況不在本文的討論範圍內。

第二種情況,接收端只收到一個數據包,由於TCP是不會出現丟包的,所以這一個數據包中包含了發送端發送的兩個數據包的信息,這種現象即爲粘包。這種情況由於接收端不知道這兩個數據包的界限,所以對於接收端來說很難處理。

第三種情況,這種情況有兩種表現形式,如下圖。接收端收到了兩個數據包,但是這兩個數據包要麼是不完整的,要麼就是多出來一塊,這種情況即發生了拆包和粘包。這兩種情況如果不加特殊處理,對於接收端同樣是不好處理的。

 

粘包、拆包發生原因

發生TCP粘包或拆包有很多原因,現列出常見的幾點,可能不全面,歡迎補充,

1、要發送的數據大於TCP發送緩衝區剩餘空間大小,將會發生拆包。

2、待發送數據大於MSS(最大報文長度),TCP在傳輸前將進行拆包。

3、要發送的數據小於TCP發送緩衝區的大小,TCP將多次寫入緩衝區的數據一次發送出去,將會發生粘包。

4、接收數據端的應用層沒有及時讀取接收緩衝區中的數據,將發生粘包。

等等。

粘包、拆包解決辦法

通過以上分析,我們清楚了粘包或拆包發生的原因,那麼如何解決這個問題呢?解決問題的關鍵在於如何給每個數據包添加邊界信息,常用的方法有如下幾個:

1、發送端給每個數據包添加包首部,首部中應該至少包含數據包的長度,這樣接收端在接收到數據後,通過讀取包首部的長度字段,便知道每一個數據包的實際長度了。

2、發送端將每個數據包封裝爲固定長度(不夠的可以通過補0填充),這樣接收端每次從接收緩衝區中讀取固定長度的數據就自然而然的把每個數據包拆分開來。

3、可以在數據包之間設置邊界,如添加特殊符號,這樣,接收端通過這個邊界就可以將不同的數據包拆分開。

等等。

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