天天看點

粘包現象與解決粘包問題

粘包現象與解決粘包問題

粘包問題主要出現在用TCP協定傳輸中才會出現的問題,​<code>​UDP​</code>​不會出現,因為TCP傳輸中他會服務端會一次性把所有東西一并丢入緩存區,而讀取的内容大小有時候沒法準确的做到一一讀取,所有會存在粘包。

而​<code>​UDP​</code>​他傳輸的時候是吧一個個内容丢過去,不管用戶端能否完全接受到内容他都會接受他制定大小的内容,而内容大于他接受設定的大小時候多餘的東西會被丢到

注意:隻有TCP才會出現粘包現象,​<code>​UDP​</code>​永遠不會出現粘包現象

其實我們發送資料并不是直接發送給對方, 而是應用程式将資料發送到本機作業系統的緩存裡邊, 當資料量小, 發送的時間間隔短, 作業系統就會在緩存區先攢夠一個TCP段再通過網卡一起發送, 接收資料也是一樣的, 先在作業系統的緩存存着, 然後應用程式再從作業系統中取出資料

粘包現象與解決粘包問題

如果你的網絡出現短暫的異常或波動,接受資料就會出現短暫的中斷,影響你的下載下傳或者上傳的效率,但是緩沖區解決了上傳下載下傳的傳輸效率的問題,帶來了粘包問題

主要原因 : TCP稱為流失協定, 資料流會雜糅在一起, 接收端不清楚每個消息的界限, 不知道每次應該去多少位元組的資料

次要原因 : TCP為了提高傳輸效率會有一個nagle優化算法, 當多次send的資料位元組都非常少, nagle算法就會将這些資料合并成一個TCP段再發送, 這就無形中産生了黏包

接收方沒有及時接收緩沖區的包,造成多個包接收(用戶端發送了一段資料,服務端隻收了一小部分,服務端下次再收的時候還是從緩沖區拿上次遺留的資料,産生粘包)​<code>​recv​</code>​會産生黏包(如果​<code>​recv​</code>​接受的資料量(1024)小于發送的資料量,第一次隻能接收規定的資料量1024,第二次接收剩餘的資料量)

發送端需要等緩沖區滿才發送出去,造成粘包(發送資料時間間隔很短,資料也很小,會合到一起,産生粘包)send 也可能發生粘包現象。(連續send少量的資料發到輸出緩沖區,由于緩沖區的機制,也可能在緩沖區中不斷積壓,多次寫入的資料被一次性發送到網絡)

發送端需要等待緩沖區滿了才将資料發送出去, 如果發送資料的時間間隔很短, 資料很小, 就會合到一起, 産生黏包

接收方沒有及時接收緩沖區的包, 造成多個包一起接收, 如果服務端一次隻接收了一小部分, 當服務端下次想接收新的資料的時候, 拿到的還是上次緩沖區裡剩餘的内容

注意:粘包不一定發生,如果發生了: 可能是在用戶端已經粘了。 用戶端沒有粘,可能是在服務端粘了。

粘包問題的根源在于,接收端不知道發送端将要傳送的位元組流的長度,是以解決粘包的方法就是圍繞如何讓發送端在發送資料前,把自己将要發送的位元組流總大小讓接收端知曉,然後接收端來一個死循環接收完所有資料。

服務端

用戶端

效率低 : 程式運作的速度遠快于網絡傳輸的速度, 如果在發送真實資料之前先send該資料的位元組流長度, 那麼就會放大網絡延遲帶來的性能損耗

解決粘包問題的核心就是:為位元組流加上一個自定義固定長度的報頭, 報頭中就包含了該位元組流長度, 然後隻需要将整個資料加報頭 send 一次到對端, 對端先取出固定長度的報頭, 然後在取真實的資料

【溫馨提示】:​​struct子產品在前面已經介紹過了,????struct子產品傳送門​​

問題: 前面說到多次send會擴大網絡延遲帶來的效率問題, 那為什麼還要分四次 send ?

其實在前面socket收發消息的原理圖哪裡就給出了答案,資料是先發送到位元組作業系統的緩存内,時間間隔短,資料量小的會被和在一起發送,這就是TCP協定nagle優化算法做的事(有提升效率的功能,當然也帶來了黏包問題)

udp 被稱為資料報協定, 每次發送的資料都是一個資料報, 一次 sendto 對應一次 recvfrom, 不會産生黏包

udp 又被稱為不可靠協定, 不可靠在哪裡? 比如發送方發送了 10bytes 的資料, 而接收方隻接收 8bytes 的資料, 那麼剩下的兩個 bytes 将會被丢棄, 并且在不同的平台有不同的表現, 下面我們來進行試驗 :

windows平台下實驗用戶端

運作結果如下:

粘包現象與解決粘包問題

linux平台運作下實驗用戶端

粘包現象與解決粘包問題