粘包拆包及解決方案

心如__止水發表於2023-01-05

一、粘包與拆包是什麼?

TCP在接受資料的時候,有一個滑動視窗來控制接受資料的大小,這個滑動視窗你就可以理解為一個緩衝區的大小。緩衝區滿了就會把資料傳送。資料包的大小是不固定的,有時候比緩衝區大有時候小。
如果一次請求傳送的資料量比較小,沒達到緩衝區大小,TCP則會將多個請求合併為同一個請求進行傳送,這就形成了粘包問題;
如果一次請求傳送的資料量比較大,超過了緩衝區大小,TCP就會將其拆分為多次傳送,這就是拆包,也就是將一個大的包拆分為多個小包進行傳送。

舉例:

當傳送方傳送了資料包 `訊息1:ABC` 和 `訊息2:DEF` 時,但接收方接收到的資料包卻是 `訊息:ABCDEF`,像這種一次性讀取了兩條資料包的資料粘連在一起的情況就叫做粘包(正常情況應該是一條一條讀取的)。

  當傳送方傳送了資料包 ` 訊息1:ABC ` 和 `訊息2:DEF` 時,接收方接收到資料包經拆分後獲得了 `ABCD` 和 `EF` 兩個資料包資訊的情況,像這種情況有時候也叫做半包。

二、粘包與拆包為什麼發生?

1.TCP會發生粘包問題:TCP 是面向連線的傳輸協議,TCP 傳輸的資料是以流的形式,而流資料是沒有明確的開始結尾邊界,所以 TCP 也沒辦法判斷哪一段流屬於一個訊息;TCP協議是流式協議;所謂流式協議,即協議的內容是像流水一樣的位元組流,內容與內容之間沒有明確的分界標誌,需要認為手動地去給這些協議劃分邊界。
粘包時:傳送方每次寫入資料 < 接收方套接字(Socket)緩衝區大小。
拆包時:傳送方每次寫入資料 > 接收方套接字(Socket)緩衝區大小。

2.UDP不會發生粘包問題:UDP具有保護訊息邊界,在每個UDP包中就有了訊息頭(UDP長度、源埠、目的埠、校驗和)。

三、遇到粘包、拆包怎麼辦?

對於粘包和拆包問題,常見的解決方案有四種:

  1.     客戶端在傳送資料包的時候,每個包都固定長度,比如1024個位元組大小,如果客戶端傳送的資料長度不足1024個位元組,則透過補充空格的方式補全到指定長度
  2.     客戶端在每個包的末尾使用固定的分隔符,例如\r\n,如果一個包被拆分了,則等待下一個包傳送過來之後找到其中的\r\n,然後對其拆分後的頭部部分與前一個包的剩餘部分進行合併,這樣就得到了一個完整的包;
  3.     將訊息分為頭部和訊息體,在頭部中儲存有當前整個訊息的長度,只有在讀取到足夠長度的訊息之後才算是讀到了一個完整的訊息;
  4.     透過自定義協議進行粘包和拆包的處理。

 

相關文章