最近為服務(wù)器添加XMLSocket與Flash進行通信, 這種協(xié)議其實是一種以\0結(jié)尾的字符串協(xié)議, 為了讓asio兼容此協(xié)議, 我從文檔找到了async_read_until異步讀取系列, 這個函數(shù)的原理時, 給定一個streambuf, 和一個分隔符, asio碰到分隔符時返回, 你可以從streambuf中讀取需要的數(shù)據(jù). 看似很簡單, 我很快寫好一個demo與Flash進行通信, 結(jié)果發(fā)現(xiàn)在一個echo邏輯速度很快時, 服務(wù)器居然亂包了, 網(wǎng)上查了下, 官方原文是這樣的:
”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中并不一定是到分隔符前的所有數(shù)據(jù), 多余的數(shù)據(jù)可能一樣會在streambuf中. 也就是說, 還需要自己再次處理一遍數(shù)據(jù)...
動手唄, async_read_until看似就是一個廢柴, 底層已經(jīng)費了很多CPU在逐字符與分隔符的匹配上, 拋上來的數(shù)據(jù)居然還是半成品.
代碼如下, 測試通過, 但是實在很費解為啥非要再做一次..
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]; // 這里需要自己判斷字符串內(nè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構(gòu)造時加一個最大一個讀取量, 超過此量會返回報錯, 避免了緩沖區(qū)被撐爆的危險