最近為服務(wù)器添加XMLSocket與Flash進(jìn)行通信, 這種協(xié)議其實(shí)是一種以\0結(jié)尾的字符串協(xié)議, 為了讓asio兼容此協(xié)議, 我從文檔找到了async_read_until異步讀取系列, 這個(gè)函數(shù)的原理時(shí), 給定一個(gè)streambuf, 和一個(gè)分隔符, asio碰到分隔符時(shí)返回, 你可以從streambuf中讀取需要的數(shù)據(jù). 看似很簡(jiǎn)單, 我很快寫好一個(gè)demo與Flash進(jìn)行通信, 結(jié)果發(fā)現(xiàn)在一個(gè)echo邏輯速度很快時(shí), 服務(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ù)可能一樣會(huì)在streambuf中. 也就是說(shuō), 還需要自己再次處理一遍數(shù)據(jù)...
動(dòng)手唄, async_read_until看似就是一個(gè)廢柴, 底層已經(jīng)費(fèi)了很多CPU在逐字符與分隔符的匹配上, 拋上來(lái)的數(shù)據(jù)居然還是半成品.
代碼如下, 測(cè)試通過(guò), 但是實(shí)在很費(fèi)解為啥非要再做一次..
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的文檔里這么說(shuō)的
if ( DChar == '\0' )
{
DataSize = i;
break;
}
}
if ( DataSize > 0 )
{
// 取成字符串
std::string FullText( Buffs, DataSize );
// 消費(fèi)
SB->consume( DataSize );
mWorkService->post(
boost::bind(&AsioSession::NotifyReadString,
shared_from_this(),
FullText )
);
}
另外, 為了保證輸入性安全, 可以在streambuf構(gòu)造時(shí)加一個(gè)最大一個(gè)讀取量, 超過(guò)此量會(huì)返回報(bào)錯(cuò), 避免了緩沖區(qū)被撐爆的危險(xiǎn)