1、粘包產生的原因
如果客戶端連續不斷的向服務端發送數據包時,服務端接收的數據會出現兩個數據包粘在一起的情況,這就是TCP協議中經常會遇到的粘包以及拆包的問題。
傳輸層的UDP協議是否會發生粘包或者拆包問題?
不會。UDP是基於報文發送的,在UDP首部采用了16bit來指示UDP數據報文的長度,因此在應用層能很好的將不同的數據報文區分開,從而避免粘包和拆包的問題。
傳輸層的TCP協議是否會發生粘包或者拆包問題?
會。原因有以下兩點:
1、TCP是基於字節流的,雖然應用層和傳輸層之間的數據交互是大小不等的數據塊,但是TCP把這些數據塊僅僅看成一連串無結構的字節流,沒有邊界;
2、在TCP的首部沒有表示數據長度的字段,基於上面兩點,在使用TCP傳輸數據時,才有粘包或者拆包現象發生的可能。
2、粘包/拆包的表現形式
現在假設客戶端向服務端連續發送了兩個數據包,用packet1和packet2來表示,那么服務端收到的數據可以分為三種,現列舉如下:
第一種情況,接收端正常收到兩個數據包,即沒有發生拆包和粘包的現象,此種情況不在本文的討論范圍內。
第二種情況,接收端只收到一個數據包,由於TCP是不會出現丟包的,所以這一個數據包中包含了發送端發送的兩個數據包的信息,這種現象即為粘包。這種情況由於接收端不知道這兩個數據包的界限,所以對於接收端來說很難處理。
第三種情況,這種情況有兩種表現形式,如下圖。接收端收到了兩個數據包,但是這兩個數據包要么是不完整的,要么就是多出來一塊,這種情況即發生了拆包和粘包。這兩種情況如果不加特殊處理,對於接收端同樣是不好處理的。
3、粘包/拆包發生的原因
發生TCP粘包或拆包有很多原因,現列出常見的幾點:
1、要發送的數據大於TCP發送緩沖區剩余空間大小,將會發生拆包。
2、待發送數據大於MSS(最大報文長度),TCP在傳輸前將進行拆包。
3、要發送的數據小於TCP發送緩沖區的大小,TCP將多次寫入緩沖區的數據一次發送出去,將會發生粘包。
4、接收數據端的應用層沒有及時讀取接收緩沖區中的數據,將發生粘包。
4、粘包/拆包的解決辦法
通過以上分析,我們清楚了粘包或拆包發生的原因,那么如何解決這個問題呢?解決問題的關鍵在於如何給每個數據包添加邊界信息,常用的方法有如下幾個:
1、發送端給每個數據包添加包首部,首部中應該至少包含數據包的長度,這樣接收端在接收到數據后,通過讀取包首部的長度字段,便知道每一個數據包的實際長度了。
2、發送端將每個數據包封裝為固定長度(不夠的可以通過補0填充),這樣接收端每次從接收緩沖區中讀取固定長度的數據就自然而然的把每個數據包拆分開來。
3、可以在數據包之間設置邊界,如添加特殊符號,這樣,接收端通過這個邊界就可以將不同的數據包拆分開。