網絡基礎:TCP協議-粘包問題

面向字節流

創建一個socket的,不僅僅只是申請一個文件描述符,並且還開闢一片發送緩衝區及接收緩衝區。在調用write進行寫數據時,先寫入發送緩衝區當中,如果數據較大,那麼TCP進行分包發送。如果數據較小,那麼就現在發送緩衝區內部等待,等到了合適的時候再發出。在接收數據時,首先從網卡驅動程序中將數據讀至接收緩衝區,接着調用read進行讀數據。由於TCP既有發送緩衝區又有接收緩衝區,所以write與read並不衝突,可同時進行,這個就叫做全雙工。
在進行讀寫的時候,不用一次性讀完或寫完,可以分批來。這也是面向字節流的好處。

粘包問題

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

粘包問題的形式

在前面講到TCP面向字節流,並且在發送時候,先寫入到發送緩衝區內部。但是在發送緩衝區內部不一定發送,如果數據過小會等待接下來的數據。如果過大就分包,這就造成了粘包的問題。
具體形式如下:
這裏寫圖片描述
這種情況屬於正常情況,不會發生粘包問題。

這裏寫圖片描述
這種情況是因爲data1到達接收端接收緩衝區後未被處理,此時data2也到達。這樣data1與data2粘包。

這裏寫圖片描述
這種情況是因爲data1的數據太大,發送緩衝區一次發不完,於是拆包並分包。分兩次發送,第一次發送成功,第二次發送時data2也在發送緩衝區,此時data1的後面部分與data2發生粘包。

這裏寫圖片描述
這種情況是因爲data1數據過短,在發送緩衝區等待,此時data2寫入發送緩衝區,發送緩衝區滿了,導致data2後半部分分包。這樣data1與data2的前半部分發生粘包。

粘包產生的常見原因

發生TCP粘包或拆包有很多原因,列出常見原因:

  1. 要發送的數據大於TCP發送緩衝區剩餘空間大小,將會發生拆包。
  2. 待發送數據大於MSS(最大報文長度),TCP在傳輸前將進行拆包。
  3. 要發送的數據小於TCP發送緩衝區的大小,TCP將多次寫入緩衝區的數據一次發送出去,將會發生粘包。
  4. 接收數據端的應用層沒有及時讀取接收緩衝區中的數據,將發生粘包。

粘包的解決方法

解決粘包問題的核心就是明確兩個包的界限!!!

解決方式:

  1. 在接收端接收的時候採用定長的方式接收,調用read讀取時每次都是固定的長度進行讀取。
  2. 人爲的在數據包報頭添加數據包長度。
  3. 發送端在數據包邊界設置明確的分隔符,如特殊符號等。

歡迎大家共同討論,如有錯誤及時聯繫作者指出,並改正。謝謝大家!

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