最近為服務器添加XMLSocket與Flash進行通信, 這種協議其實是一種以\0結尾的字符串協議, 為了讓asio兼容此協議, 我從文檔找到了async_read_until異步讀取系列, 這個函數的原理時, 給定一個streambuf, 和一個分隔符, asio碰到分隔符時返回, 你可以從streambuf中讀取需要的數據. 看似很簡單, 我很快寫好一個demo與Flash進行通信, 結果發現在一個echo邏輯速度很快時, 服務器居然亂包了, 網上查了下, 官方原文是這樣的:
”After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter. An application will typically leave that data in the streambuf for a subsequent async_read_until operation to examine.”
意思是, streambuf中并不一定是到分隔符前的所有數據, 多余的數據可能一樣會在streambuf中. 也就是說, 還需要自己再次處理一遍數據...
動手唄, async_read_until看似就是一個廢柴, 底層已經費了很多CPU在逐字符與分隔符的匹配上, 拋上來的數據居然還是半成品.
代碼如下, 測試通過, 但是實在很費解為啥非要再做一次..
boost::asio::streambuf* SB = SBP.get(); // 訪問緩沖 const char* Buffs = boost::asio::buffer_cast<const char*>( SB->data() ); uint32 DataSize = 0; for ( uint32 i = 0; i < SB->size(); ++i ) { const char DChar = Buffs[i]; // 這里需要自己判斷字符串內容, read_until的文檔里這么說的 if ( DChar == '\0' ) { DataSize = i; break; } } if ( DataSize > 0 ) { // 取成字符串 std::string FullText( Buffs, DataSize ); // 消費 SB->consume( DataSize ); mWorkService->post( boost::bind(&AsioSession::NotifyReadString, shared_from_this(), FullText ) ); }
另外, 為了保證輸入性安全, 可以在streambuf構造時加一個最大一個讀取量, 超過此量會返回報錯, 避免了緩沖區被撐爆的危險