粘包和拆包

2022-07-15 09:42:13 字數 1976 閱讀 2701

tcp 是個"流"協議,所謂流,就是沒有界限的一串資料(無論你上層是如何封裝的資料,到通訊層都會轉換成「流」的形式,比如 netty 的 bytebuf),它會根據 tcp 緩衝區的實際情況進行包的劃分,所以實際場景可能是:

上面我們詳細了解了 tcp 粘包與拆包,那麼為什麼會發生粘包和拆包呢,大致上有三個方面的原因:

即上文描述的那種情況。

nagle演算法,tcp 預設開啟 nagle 演算法,nagle 演算法主要做兩件事情:只有上乙個分組得到確認,才傳送下乙個分組,收集多個小分組,在乙個確認到來時一起傳送,nagle 演算法可能造成傳送方粘包。

進行mss(max segment size)tcp 包,mss 是最大 tcp 分段,是 tcp 報文段中的資料字段最大長度,mss = tcp 報文段長度 - tcp 首部長度,同樣 mss = mtu - ip header頭大小 - tcp 頭大小。

注意,mss 是 tcp 傳輸層的概念,tcp 為了避免被傳送方分片,會主動把資料分割成小段再交給網路層,最大的分段大小稱之為 mss(max segment size)。

乙太網的 payload 大於mtu,進行 ip 分片(mtu概念不清楚的可以看一下這篇文章)。

mtu 是資料鏈路層概念。

無論是 tcp 拆包還是 tcp 粘包本質問題都在於無法區分包的邊界,一般有三種區分包邊界的方式:

訊息資料固定長度,實際應用中基本不可能做到,即時做到了,也是很浪費儲存和網路資源。

使用分割符來區分包的界限

資料報的頭部中增加資料報長度字段

tcp 之所以存在拆包和粘包問題,本質就是 tcp 是面向位元組流的協議,位元組流協議即無邊界協議;而像 udp 是面向報文的,當客戶端連續傳送多個包,並不會發生粘包現象,每乙個包都是獨立的,傳送的時候也是以乙個乙個包為單位。

那麼問題來了,不會發生粘包,如果應用程式 write 乙個大的包,那麼到底層進行傳送的時候會不會發生拆包呢?

答案是:不會。udp 協議傳送時,用 sendto 函式最大能傳送資料的長度為:65535- ip 頭(20) - udp 頭(8) = 65507 位元組。用 sendto 函式傳送資料時,如果傳送資料長度大於該值,則函式直接返回錯誤,不會發生拆包,而 tcp 流協議是會發生拆包的。

sendto是乙個計算機函式,指向一指定目的地傳送資料,sendto 適用於傳送未建立連線的 udp 資料報 (引數為sock_dgram)。sendto 傳送資料必需注意資料長度不應超過通訊子網的 ip 包最大長度。ip 包最大長度在 wsastartup() 呼叫返回的 wsadata 的 imaxudpdg 元素中。如果資料太長無法自動通過下層協議,則返回wsaemsgsize錯誤,資料不會被傳送。

wsaemsgsize:套介面為 sock_dgram 型別,且資料報大於 windows 套介面實現所支援的最大值。

int pascal far sendto(socket s, const char far* buf, int len, int flags, const struct sockaddr far* to, int tolen);
s:乙個標識套介面的描述字

buf:含待傳送資料的緩衝區

len:buf 緩衝區中資料的長度

flags:呼叫方式標誌位

到這裡關於 tcp 粘包和拆包是什麼,產生的原因是什麼,以及 udp 是否也會發生粘包和拆包的問題做了簡要分析。這只是關於 tcp 粘包和拆包問題的第一篇文章,後面會詳細分析常用的解決方案,以及市面上常用通訊框架的解決方案是什麼。

參考

粘包和拆包

3.圖三是發生了粘包的現象。客戶端傳送p1,p2包,p1,p2包到達接收端的快取,服務端應用讀取快取時無法區分p1,p2各自的大小。因為在tcp通訊協議中tcp是面向流的,包和包之間沒有界限。粘包可發生在傳送端也可發生在接收端以圖三各舉例子 傳送端原因導致的粘包,客戶端在傳送p1包時,先將p1包放入...

TCP粘包和拆包

當傳送包同時傳送兩個資料報時,接收包只收到了乙個資料報,其中包含了兩個資料報的資訊,這種現象為粘包。這種情況下,接收方無法分清兩個資料報的界限,很難處理 當傳送包同時傳送兩個資料報時,接收方也收到了兩個資料報。但是這兩個資料報,乙個是不完整的,乙個是多出來一塊,這種現象為拆包。訊息定長 傳送方將資料...

TCP粘包 拆包

tcp粘包 拆包 客戶端發服務端傳送了兩個資料報a和b 粘包 服務端一次性接收到了a和b 拆包 服務端第一次接收了a和b的一部分,第二次接收到了b的剩餘部分 粘包 拆包原因 1 應用程式寫入的位元組大小 socket傳送緩衝區大小 2 tcp分段 tcp data部分的大小 mss max segm...