TCP的粘包拆包技術
導讀 | TCP 是一個面向「流」的協議,所謂流就是沒有界限的一長串二進位制資料。在實際的傳輸過程中,TCP 會根據網路情況將資料包進行拆分或者拼裝,如果業務沒有定義一個明確的界限規則,在應用層的業務上就會出現粘包拆包的現象。 |
平時大家在網路程式設計過程中可能會遇到這樣一種現象:客戶端傳送了一長串訊息,服務端接受的訊息揉在一起或者被拆分了,這樣就會造成訊息難以被正確理解。比如說有一天你特別想喝奶茶,看了一下外賣,「一點點」的奶茶看著不錯,(一點點趕緊給我打錢 doge),於是你在群裡發了一條訊息,想找幾個人拼奶茶:
一點點奶茶有人喝嗎?
結果群裡同事回了一句:現在不是已經三點了嗎?
你覺得莫名其妙,看了一眼同事的手機,他收到的訊息是這樣的兩行:
一點
點奶茶有人喝嗎?
哈哈,講了一個冷笑話。用專業的術語來說這種現象就是「拆包」了,我們接著往下講。
粘包拆包問題一般是處於應用層下的問題,在資料鏈路層、網路層以及傳輸層都有可能發生。我們日常的網路應用開發大多都在傳輸層進行,因此本文著重講解傳輸層粘包拆包問題。
傳輸層有兩個協議我們都很熟悉:UDP 和 TCP,UDP有訊息保護邊界,不會發生粘包拆包問題,因此粘包拆包問題只發生在TCP協議中。
下面用一個簡單的例子來講解什麼是粘包和拆包。
假設客戶端向服務端連續傳送了兩個資料包,用 packet1 和 packet2 來表示,那麼服務端收到的資料可能有四種:
(1)第一種情況,服務端按順序正常收到兩個包,即未出現粘包和拆包的現象。
(2)第二種情況,服務端只收到一個資料包,由於 TCP 保證送達的特性,所以這一個資料包包含了客戶端傳送的兩個資料包的資訊,這種現象就是粘包。除非客戶端傳送的資料包有明確的規則,否則服務端不知道兩個包的界限,難以處理資料。
(3)第三種情況,服務端收到了三個資料包,Package1資料包被拆分為兩個資料包:Package1.1和Package1.2,這種現象就是拆包,至於拆包的原因下面會講,服務端收到拆開的資料包也很難處理。
(4)第四種情況,一些大的資料包被拆分為小的資料包,小的資料包與其他資料包粘在一起,這種現象是將上面的粘包和拆包綜合在一塊。
TCP 是一個面向「流」的協議,所謂流就是沒有界限的一長串二進位制資料。TCP 作為傳輸層協議並不瞭解上層業務資料的具體含義,它會根據TCP緩衝區的實際情況進行資料包的劃分,所以在業務上認為是一個完整的包,可能會被 TCP 拆分成多個包進行傳送,也有可能把多個小的包封裝成一個大的資料包傳送,這就會出現粘包拆包的問題。
例如,TCP緩衝區是1024個位元組大小,如果應用一次請求傳送的資料量比較小,沒達到緩衝區大小,TCP則會將多個請求合併為同一個請求進行傳送,站在業務上來看這就是「粘包」;
如果應用一次請求傳送的資料量比較大,超過了緩衝區大小,TCP就會將其拆分為多次傳送,這就是「拆包」,也就是將一個大的包拆分為多個小包進行傳送。
TCP 是面向流的,會發生粘包和拆包,那作為應用程式,如何從這源源不斷湧來的資料流中拆分出或者合併出有意義的資訊呢?通常會有以下一些常用的方法:
(1)傳送端給每個資料包新增包首部,首部中應該至少包含資料包的長度,這樣接收端在接收到資料後,通過讀取包首部的長度欄位,便知道每一個資料包的實際長度了。
如下圖,在每個包前面加上包的實際長度。
(2)傳送端將每個資料包封裝為固定長度(不夠的可以通過補0填充),這樣接收端每次從接收緩衝區中讀取固定長度的資料就自然而然的把每個資料包拆分開來。
下圖每個包的固定長度為 4,接收端很容易進行區分。
(3)可以在資料包之間設定邊界,如新增特殊符號,這樣,接收端通過這個邊界就可以將不同的資料包拆分開。
如下圖,在每個包的後面加上特殊字元:/
Netty 作為一款高效能的 Java 網路程式設計框架,不僅是基於 Java NIO 進行了深度封裝,還在客戶端與服務端之間的資料傳輸上做了有效處理。
前面講過 TCP 傳輸會出現粘包和拆包的現象,Netty 針對這一點內建了多款資料流編解碼器,客戶端服務端按照約定好的規則進行資料傳輸即可解決這個問題。
Netty 提供了多款開箱即用的編解碼器:
- (1)FixedLengthFrameDecoder 固定長度解碼器
- (2)DelimiterBasedFrameDecoder 指定分隔符解碼器
- (3)LengthFieldBasedFrameDecoder 基於資料包長度解碼器
- (4)等等……這裡不再列舉
TCP 是一個面向「流」的協議,所謂流就是沒有界限的一長串二進位制資料。在實際的傳輸過程中,TCP 會根據網路情況將資料包進行拆分或者拼裝,如果業務沒有定義一個明確的界限規則,在應用層的業務上就會出現粘包拆包的現象。
針對 TCP 粘包拆包的現象,常見的解決思路如下:
- (1)傳送端給每個資料包新增包首部。
- (2)傳送端將每個資料包封裝為固定長度。
- (3)可以在資料包之間設定邊界。
為了解決粘包拆包,Netty 框架也提供了很多開箱即用的編解碼器,極大簡化網路程式設計解決此類問題的難度。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2893837/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- TCP 粘包拆包TCP
- TCP粘包拆包問題TCP
- go語言處理TCP拆包/粘包GoTCP
- TCP 粘包 - 拆包問題及解決方案TCP
- Netty - 粘包與拆包Netty
- Netty 中的粘包和拆包Netty
- 計算機網路 - TCP粘包、拆包以及解決方案計算機網路TCP
- 粘包拆包及解決方案
- Netty(三) 什麼是 TCP 拆、粘包?如何解決?NettyTCP
- Netty如何解決粘包拆包?(二)Netty
- 粘包/拆包問題一直都存在,只是到TCP就拆不動了。TCP
- 深入學習Netty(5)——Netty是如何解決TCP粘包/拆包問題的?NettyTCP
- Netty拾遺(七)——粘包與拆包問題Netty
- Go TCP 粘包問題GoTCP
- Netty解決粘包和拆包問題的四種方案Netty
- 詳說tcp粘包和半包TCP
- Netty2:粘包/拆包問題與使用LineBasedFrameDecoder的解決方案Netty
- TCP協議粘包問題詳解TCP協議
- Netty入門系列(2) --使用Netty解決粘包和拆包問題Netty
- [ gev ] Go 語言優雅處理 TCP “粘包”GoTCP
- 硬核圖解TCP粘包 資料包:我只是犯了每個資料包都會犯的錯圖解TCP
- 粘包問題
- Netty中使用MessagePack時的TCP粘包問題與解決方案NettyTCP
- C# 優雅的處理TCP資料(心跳,超時,粘包斷包,SSL加密 ,資料處理等)C#TCP加密
- 結合RPC框架通訊談 netty如何解決TCP粘包問題RPC框架NettyTCP
- Socket 粘包和分包問題
- Netty粘包&半包解決方案Netty
- Netty Protobuf處理粘包分析Netty
- Python:列表也能拆包?Python
- Python元組和字典的拆包Python
- socket的半包,粘包與分包的問題
- 從零開始實現簡單 RPC 框架 7:網路通訊之自定義協議(粘包拆包、編解碼)RPC框架協議
- 粘包問題原因和解決方法
- 25. Socket與粘包問題
- netty 解決粘包 和 分包的問題Netty
- PHP拆紅包演算法PHP演算法
- APP常用抓包技術APP
- java nio解決半包 粘包問題Java