天天看點

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來表示,那麼服務端收到的資料可以分為三種,現列舉如下:

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

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

第二種情況,接收端隻收到一個資料包,由于TCP是不會出現丢包的,是以這一個資料包中包含了發送端發送的兩個資料包的資訊,這種現象即為粘包。這種情況由于接收端不知道這兩個資料包的界限,是以對于接收端來說很難處理。

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

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

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

粘包、拆包發生原因

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

1、要發送的資料大于TCP發送緩沖區剩餘空間大小,将會發生拆包。

2、待發送資料大于MSS(最大封包長度),TCP在傳輸前将進行拆包。

3、要發送的資料小于TCP發送緩沖區的大小,TCP将多次寫入緩沖區的資料一次發送出去,将會發生粘包。

4、接收資料端的應用層沒有及時讀取接收緩沖區中的資料,将發生粘包。

等等。

粘包、拆包解決辦法

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

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

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

3、可以在資料包之間設定邊界,如添加特殊符号,這樣,接收端通過這個邊界就可以将不同的資料包拆分開。

等等。