針對三種不同的粘包現象,分包演算法分別採取了相應的解決辦法。其基本思路是首先將待處理的接收資料流(長度設為m)強行轉換成預定的結構資料形式,並從中取出結構資料長度字段,而後根據n計算得到第一包資料長度。
1)若nm,則表明資料流內容尚不夠構成一完整結構資料,需留待與下一包資料合併後再行處理。
也就是說,n也是資料報中的一部分內容,個人覺得,常見的tcp分包一般都是對應的tcp粘包問題而提出來的。
tcp粘包是指傳送方傳送的若干包資料到接收方接收時粘成一包,從接收緩衝區看,後一包資料的頭緊接著前一包資料的尾。粘包可能由傳送方造成,也可能由接收方造成。tcp為提高傳輸效率,傳送方往往要收集到足夠多的資料後才傳送一包資料,造成多個資料報的粘連。如果接收程序不及時接收資料,已收到的資料就放在系統接收緩衝區,使用者程序讀取資料時就可能同時讀到多個資料報。因為系統傳輸的資料是帶結構的資料,需要做分包處理。
為了適應高速複雜網路條件,我們設計實現了粘包處理模組,由接收方通過預處理過程,對接收到的資料報進行預處理,將粘連的包分開。為了方便粘包處理,提高處理效率,在接收環節使用了環形緩衝區來儲存接收到的資料。其結構如表1所示。
表1 環形緩衝結構
欄位名型別
含義cs
critical_section
保護環形緩衝的臨界區
pringbuf
uint8*
緩衝區起始位置
pread
uint8*
當前未處理資料的起始位置
pwrite
uint8*
當前未處理資料的結束位置
plastwrite
uint8*
當前緩衝區的結束位置
環形緩衝跟每個tcp套接字繫結。在每個tcp的socket_obj建立時,同時建立乙個pringbuffer結構並初始化。這時候,pringbuf指向環形緩衝區的記憶體首位址,pread、pwrite指標也指向它。plastwrite指標在這時候沒有實際意義。初始化之後的結構如圖1所示。
圖1 初始化後的環形緩衝區
在每次投遞乙個tcp的接收操作時,從ringbuffer獲取記憶體作接收緩衝區,一般規定乙個最大值l1作為可以寫入的最大資料量。這時把pwrite的值賦給buffer_obj的buf欄位,把l1賦給buflen欄位。這樣每次接收到的資料就從pwrite開始寫入緩衝區,最多寫入l1位元組,如圖2。
圖2分配緩衝後的環形緩衝
如果某次分配過程中,pwrite到緩衝區結束的位置pend長度不夠最小分配長度l1,為了提高接收效率,直接廢棄最後一段記憶體,標記plastwrite為pwrite。然後從pringbuf開始分配記憶體,如圖3。
圖3 使用到結尾的環形緩衝
特殊情況下,如果處理包速度太慢,或者接收太快,可能導致未處理包占用大部分緩衝區,沒有足夠的緩衝區分配給新的接收操作,如圖4。這時候直接報告錯誤即可。
圖4沒有足夠接收緩衝的環形緩衝
當收到乙個長度為l資料報時,需要修改緩衝區的指標。這時候已經寫入資料的位置變為(pwrite+l),如圖5。
圖5收到長度為l的資料的環形緩衝
分析上述環形緩衝的使用過程,收到資料後的情況可以簡單歸納為兩種:pwrite>pread,接收但未處理的資料位於pread到pwrite之間的緩衝區;pwrite,這時候,資料位於pread到plastwrite和pringbuf到pwrite之間。這兩種情況分別對應圖6、圖7。
首先分析圖6。此時,pread是乙個包的起始位置,如果l1足夠乙個包頭長度,就獲取該包的長度資訊,記為l。假如l1>l,就說明乙個資料報接收完成,根據包型別處理包,然後修改pread指標,指向下乙個包的起始位置(pread+l)。這時候仍然類似於之前的狀態,於是解包繼續,直到l1不足乙個包的長度,或者不足包頭長度。這時退出解包過程,等待後續的資料到來。
圖6有未處理資料的環形緩衝(1)
圖7有未處理資料的環形緩衝(2)
圖8稍微複雜。首先按照上述過程處理l1部分。存在一種情況,經過若干個包處理之後,l1不足乙個包,或者不足乙個包頭。如果這時(l1+l2)足夠乙個包的長度,就需要繼續處理。另外申請乙個最大包長度的記憶體區ptemp,把l1部分和l2的一部分複製到ptemp,然後執行解包過程。
經過上述解包之後,pread就轉向pringbuf到pwrite之間的某個位置,從而回歸情況圖6,繼續按照圖6部分執行解包。
TCP粘包分包現象
服務端,接收資料,在每次接收到的資料末尾添上乙個 尾 字 客戶端傳送資料,將同樣的資料連續傳送若干次 不是將資料複製若干份一次傳送 using system using system.collections.generic using system.componentmodel using syst...
TCP原理 粘包分包現象
參考 雲棲社群 就是要你懂 tcp 最經典的tcp效能問題 粘包現象產生的原因 由於tcp協議本身的機制 三次握手 客戶端與伺服器會維持乙個連線 channel 資料在連線不斷開的情況下,可以持續不斷地將多個資料報發往伺服器,但是如果傳送的網路資料報太小,那麼他本身會啟用nagle演算法 可配置是否...
Qt的TCP粘包分包
粘包只可能出現在流傳輸中,tcp是基於流傳輸的,而udp是不會出現粘包,因為udp是基於報文的,也就是說udp傳送端呼叫幾次write,接收端必須呼叫相同次數的read讀完,每次最多只能讀取乙個報文,報文與報文是不會合併的,如果緩衝區小於報文長度,則多出來的部分會被丟掉。tcp不同了,它會合併訊息,...