在使用tcp協議的網路應用中,不可避免需要處理的乙個問題就是半包和粘包的情況。
一種做法是在接收端設乙個比較大的緩衝區,先將收到的資料報都放到緩衝區中,然後從該緩衝區中選取完整的資料報出來。該緩衝區的實現可以使用環形緩衝區進行優化,避免頻繁的資料移動。使用該方法的乙個描述見
另外一種做法就是在接收的時候就只接收完整包。這要求資料報有固定的包頭結構體,其中還要包含資料報的長度資訊。在服務端接收的時候,先接收該包頭資料,然後再接收指定長度的資料體。
在ace中,用於儲存訊息的ace_message_block有乙個重要的特性:復合。即將多條訊息連線在一起,形成乙個單鏈表。這樣便可以將先收到的包頭和後收到的包體連成乙個複合體,而不用建乙個大的資料報,將兩個message_block拷貝進去。
下面的示例採用ace的proactor框架完成,實現了伺服器端半包及粘包的處理,以及ace_message_block的復合,網路io與邏輯處理的分離。
在proactor框架中,接收新連線後,會初始化乙個讀請求,此時只要求讀包頭長度的資料:
void init_read_stream()
這裡由於使用了網路io與邏輯處理分執行緒處理的方式,遞交給邏輯執行緒的資料報前面還加上了標識網路連線的handle,用以告訴邏輯執行緒該資料報是哪個客戶端連線發上來的。
遞交給邏輯執行緒的資料報頭結構為:
struct packetheader
;其中data_length就是從接收到的資料報中獲取到的。
對於粘包的情況比較容易處理,先收了包頭後再接收指定長度的資料報,多餘的資料由下次再讀取。
半包情況稍微複雜一點,每個資料報是分兩次接收的,兩次接收的時候都有可能接收不完全。
當接收包頭不完全時所做的處理是繼續提交讀請求,讀的資料長度為剩餘的包頭長度
if (this->recv_data_->length() < sizeof(packetheader))
當包頭接收完後,新建乙個message_block,長度為需要接收的資料體長度,並將該message_block鏈結到包頭後
packetheader * hdr = reinterpret_cast(this->recv_data_->rd_ptr());
ace_message_block * data_mb = this->recv_data_->cont();
if (!data_mb)
如果該資料報的包體接收完全,則將該完整的資料報傳送到邏輯執行緒的訊息佇列,然後初始化乙個新的接收請求
if (data_mb->length () == hdr->data_length)
否則表示資料體還未接收完全,處理方法也是繼續提交剩餘資料的讀請求
this->reader_.read (*data_mb, data_mb->space ());
直接該資料報讀取完全。
資料報接收處理函式的完整實現為:
virtual void handle_read_stream (const ace_asynch_read_stream::result &result)
else
packetheader * hdr = reinterpret_cast(this->recv_data_->rd_ptr());
ace_message_block * data_mb = this->recv_data_->cont();
if (!data_mb)
if (data_mb->length () == hdr->data_length)
// 否則繼續接收該資料報
this->reader_.read (*data_mb, data_mb->space ());}}
完整的伺服器實現和模擬半包及粘包情況的客戶端**見
伺服器僅實現了最簡單的資料接收功能,為精減**,未做錯誤檢查
資料接收中粘包及半包的處理
在使用tcp協議的網路應用中,不可避免需要處理的乙個問題就是半包和粘包的情況。一種做法是在接收端設乙個比較大的緩衝區,先將收到的資料報都放到緩衝區中,然後從該緩衝區中選取完整的資料報出來。該緩衝區的實現可以使用環形緩衝區進行優化,避免頻繁的資料移動。使用該方法的乙個描述見 http www.vckb...
資料接收中粘包及半包的處理
在使用tcp協議的網路應用中,不可避免需要處理的乙個問題就是半包和粘包的情況。一種做法是在接收端設乙個比較大的緩衝區,先將收到的資料報都放到緩衝區中,然後從該緩衝區中選取完整的資料報出來。該緩衝區的實現可以使用環形緩衝區進行優化,避免頻繁的資料移動。使用該方法的乙個描述見 另外一種做法就是在接收的時...
半包粘包處理
資料接收中粘包及半包的處理 資料接收中粘包及半包的處理 2006 10 16 09 45 在使用tcp協議的網路應用中,不可避免需要處理的乙個問題就是半包和粘包的情況。一種做法是在接收端設乙個比較大的緩衝區,先將收到的資料報都放到緩衝區中,然後從該緩衝區中選取完整的資料報出來。該緩衝區的實現可以使用...