tcp粘包和拆包的處理方案

2021-08-25 22:33:17 字數 2511 閱讀 7709

隨著智慧型硬體越來越流行,很多後端開發人員都有可能接觸到socket程式設計。而很多情況下,伺服器與端上需要保證資料的有序,穩定到達,自然而然就會選擇基於tcp/ip協議的socekt開發。開發過程中,經常會遇到tcp粘包,拆包的問題,本文將從產生原因,和解決方案以及workerman是如何處理粘包拆包問題的,這幾個層面來說明這個問題。

什麼是粘包拆包

對於什麼是粘包、拆包問題,我想先舉兩個簡單的應用場景:

客戶端和伺服器建立乙個連線,客戶端傳送一條訊息,客戶端關閉與服務端的連線。

客戶端和伺服器簡歷乙個連線,客戶端連續傳送兩條訊息,客戶端關閉與服務端的連線。

對於第一種情況,服務端的處理流程可以是這樣的:當客戶端與服務端的連線建立成功之後,服務端不斷讀取客戶端傳送過來的資料,當客戶端與服務端連線斷開之後,服務端知道已經讀完了一條訊息,然後進行解碼和後續處理...。對於第二種情況,如果按照上面相同的處理邏輯來處理,那就有問題了,我們來看看第二種情況下客戶端傳送的兩條訊息遞交到服務端有可能出現的情況:

第一種情況:

服務端一共讀到兩個資料報,第乙個包包含客戶端發出的第一條訊息的完整資訊,第二個包包含客戶端發出的第二條訊息,那這種情況比較好處理,伺服器只需要簡單的從網路緩衝區去讀就好了,第一次讀到第一條訊息的完整資訊,消費完再從網路緩衝區將第二條完整訊息讀出來消費。

沒有發生粘包、拆包示意圖

第二種情況:

服務端一共就讀到乙個資料報,這個資料報包含客戶端發出的兩條訊息的完整資訊,這個時候基於之前邏輯實現的服務端就蒙了,因為服務端不知道第一條訊息從哪兒結束和第二條訊息從哪兒開始,這種情況其實是發生了tcp粘包。

tcp粘包示意圖

第三種情況:

服務端一共收到了兩個資料報,第乙個資料報只包含了第一條訊息的一部分,第一條訊息的後半部分和第二條訊息都在第二個資料報中,或者是第乙個資料報包含了第一條訊息的完整資訊和第二條訊息的一部分資訊,第二個資料報包含了第二條訊息的剩下部分,這種情況其實是傳送了tcp拆,因為發生了一條訊息被拆分在兩個包裡面傳送了,同樣上面的伺服器邏輯對於這種情況是不好處理的。

tcp拆包示意圖

產生tcp粘包和拆包的原因

我們知道tcp是以流動的方式傳輸資料,傳輸的最小單位為乙個報文段(segment)。tcp header中有個options標識位,常見的標識為mss(maximum segment size)指的是,連線層每次傳輸的資料有個最大限制mtu(maximum transmission unit),一般是1500位元,超過這個量要分成多個報文段,mss則是這個最大限制減去tcp的header,光是要傳輸的資料的大小,一般為1460位元。換算成位元組,也就是180多位元組。

tcp為提高效能,傳送端會將需要傳送的資料傳送到緩衝區,等待緩衝區滿了之後,再將緩衝中的資料傳送到接收方。同理,接收方也有緩衝區這樣的機制,來接收資料。

發生tcp粘包、拆包主要是由於下面一些原因:

應用程式寫入的資料大於套接字緩衝區大小,這將會發生拆包。

應用程式寫入資料小於套接字緩衝區大小,網絡卡將應用多次寫入的資料傳送到網路上,這將會發生粘包。

進行mss(最大報文長度)大小的tcp分段,當tcp報文長度-tcp頭部長度》mss的時候將發生拆包。

接收方法不及時讀取套接字緩衝區資料,這將發生粘包。

如何解決拆包粘包

既然知道了tcp是無界的資料流,且協議本身無法避免粘包,拆包的發生,那我們只能在應用層資料協議上,加以控制。通常在制定傳輸資料時,可以使用如下方法:

使用帶訊息頭的協議、訊息頭儲存訊息開始標識及訊息長度資訊,服務端獲取訊息頭的時候解析出訊息長度,然後向後讀取該長度的內容。

設定定長訊息,服務端每次讀取既定長度的內容作為一條完整訊息。

設定訊息邊界,服務端從網路流中按訊息編輯分離出訊息內容。

a)先基於第三種方法,假設區分資料邊界的標識為換行符"\n"(注意請求資料本身內部不能包含換行符),資料格式為json,例如下面是乙個符合這個規則的請求包。

\n
注意上面的請求資料末尾有乙個換行字元(在php中用雙引號字串"\n"表示),代表乙個請求的結束。

b)基於第一種方法,可以制定,首部固定10個位元組長度用來儲存整個資料報長度,位數不夠補0的資料協議

0000000036
c)基於第一種方法,可以制定,首部4位元組網路位元組序unsigned int,標記整個包的長度

****
其中首部四位元組*號代表乙個網路位元組序的unsigned int資料,為不可見字元,緊接著是json的資料格式的包體資料。

tcp粘包和拆包的處理方案

隨著智慧型硬體越來越流行,很多後端開發人員都有可能接觸到socket程式設計。而很多情況下,伺服器與端上需要保證資料的有序,穩定到達,自然而然就會選擇基於tcp ip協議的socekt開發。開發過程中,經常會遇到tcp粘包,拆包的問題,本文將從產生原因,和解決方案以及workerman是如何處理粘包...

tcp粘包和拆包的處理方案

產生tcp粘包和拆包的原因 我們知道tcp是以流動的方式傳輸資料,傳輸的最小單位為乙個報文段 segment tcp header中有個options標識位,常見的標識為mss maximum segment size最大訊息長度 指的是,連線層每次傳輸的資料有個最大限制mtu maximum tr...

TCP粘包的拆包處理

因為tcp是流式處理的,所以包沒有邊界,必須設計乙個包頭,裡面表示包的長度 一般用位元組表示 根據這個來逐個拆包。如果對於傳送 接收頻率不高的話,一般也就不做拆包處理了,因為不大可能有粘包現象。以下是粘包和拆包的分析 用qt的tcpsocket讀出的資料來拆 1 m imp m thread boo...