數據接收之環形緩衝 TCP粘包處理-RingBuf方法

TCP粘包是指發送方發送的若干包數據到接收方接收時粘成一包,從接收緩衝區看,後一包數據的頭緊接着前一包數據的尾。粘包可能由發送方造成,也可能由接收方造成。TCP爲提高傳輸效率,發送方往往要收集到足夠多的數據後才發送一包數據,造成多個數據包的粘連。如果接收進程不及時接收數據,已收到的數據就放在系統接收緩衝區,用戶進程讀取數據時就可能同時讀到多個數據包。因爲系統傳輸的數據是帶結構的數據,需要做分包處理。

爲了適應高速複雜網絡條件,我們設計實現了粘包處理模塊,由接收方通過預處理過程,對接收到的數據包進行預處理,將粘連的包分開。爲了方便粘包處理,提高處理效率,在接收環節使用了環形緩衝區來存儲接收到的數據。其結構如表1所示。

                                                            環形緩衝結構

字段名

類型

含義

CS

CRITICAL_SECTION

保護環形緩衝的臨界區

pRingBuf

UINT8*

緩衝區起始位置

pRead

UINT8*

當前未處理數據的起始位置

pWrite

UINT8*

當前未處理數據的結束位置

pLastWrite

UINT8*

當前緩衝區的結束位置

環形緩衝跟每個TCP套接字綁定。在每個TCPSOCKET_OBJ創建時,同時創建一個PRINGBUFFER結構並初始化。這時候,pRingBuf指向環形緩衝區的內存首地址,pReadpWrite指針也指向它。pLastWrite指針在這時候沒有實際意義。初始化之後的結構如圖1所示。

TCP粘包處理-RingBuf方法 - 輝煌至芯 - 輝煌至芒

初始化後的環形緩衝區

在每次投遞一個TCP的接收操作時,從RINGBUFFER獲取內存作接收緩衝區,一般規定一個最大值L1作爲可以寫入的最大數據量。這時把pWrite的值賦給BUFFER_OBJbuf字段,把L1賦給bufLen字段。這樣每次接收到的數據就從pWrite開始寫入緩衝區,最多寫入L1字節,如圖 2

TCP粘包處理-RingBuf方法 - 輝煌至芯 - 輝煌至芒

2 分配緩衝後的環形緩衝

如果某次分配過程中,pWrite到緩衝區結束的位置pEnd長度不夠最小分配長度L1,爲了提高接收效率,直接廢棄最後一段內存,標記pLastWritepWrite。然後從pRingBuf開始分配內存,如圖 3

TCP粘包處理-RingBuf方法 - 輝煌至芯 - 輝煌至芒

 使用到結尾的環形緩衝

特殊情況下,如果處理包速度太慢,或者接收太快,可能導致未處理包占用大部分緩衝區,沒有足夠的緩衝區分配給新的接收操作,如圖4。這時候直接報告錯誤即可。

TCP粘包處理-RingBuf方法 - 輝煌至芯 - 輝煌至芒

 4沒有足夠接收緩衝的環形緩衝

當收到一個長度爲L數據包時,需要修改緩衝區的指針。這時候已經寫入數據的位置變爲(pWrite+L),如圖 5

TCP粘包處理-RingBuf方法 - 輝煌至芯 - 輝煌至芒

 5收到長度爲L的數據的環形緩衝

分析上述環形緩衝的使用過程,收到數據後的情況可以簡單歸納爲兩種:pWrite>pRead,接收但未處理的數據位於pReadpWrite之間的緩衝區;pWrite<pRead,這時候,數據位於pReadpLastWritepRingbufpWrite之間。這兩種情況分別對應圖6、圖 7

首先分析圖6。此時,pRead是一個包的起始位置,如果L1足夠一個包頭長度,就獲取該包的長度信息,記爲L。假如L1>L,就說明一個數據包接收完成,根據包類型處理包,然後修改pRead指針,指向下一個包的起始位置(pRead+L)。這時候仍然類似於之前的狀態,於是解包繼續,直到L1不足一個包的長度,或者不足包頭長度。這時退出解包過程,等待後續的數據到來。

TCP粘包處理-RingBuf方法 - 輝煌至芯 - 輝煌至芒

 6有未處理數據的環形緩衝(1

TCP粘包處理-RingBuf方法 - 輝煌至芯 - 輝煌至芒

 7有未處理數據的環形緩衝(2

 8稍微複雜。首先按照上述過程處理L1部分。存在一種情況,經過若干個包處理之後,L1不足一個包,或者不足一個包頭。如果這時(L1+L2)足夠一個包的長度,就需要繼續處理。另外申請一個最大包長度的內存區pTemp,把L1部分和L2的一部分複製到pTemp,然後執行解包過程。

經過上述解包之後,pRead就轉向pRingBufpWrite之間的某個位置,從而回歸情況圖 6,繼續按照圖 6部分執行解包。

感謝http://hi.baidu.com/guangbinw/blog/item/c42ccdf4baf1d7e27609d79c.html



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章