最近為服務器添加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 )
);
} www.2cto.com
另外, 為了保證輸入性安全, 可以在streambuf構造時加一個最大一個讀取量, 超過此量會返回報錯, 避免了緩沖區被撐爆的危險