战魂小筑

讨论群:309800774 知乎关注:http://zhihu.com/people/sunicdavy 开源项目:https://github.com/davyxu

   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  257 随笔 :: 0 文章 :: 506 评论 :: 0 Trackbacks

最近为服务器添加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构造时加一个最大一个读取量, 超过此量会返回报错, 避免了缓冲区被撑爆的危险
posted on 2012-12-03 15:12 战魂小筑 阅读(11424) 评论(5)  编辑 收藏 引用 所属分类: 网络 服务器技术C++/ 编程语言

评论

# re: 恼人的boost::asio::async_read_until 2012-12-03 19:24 FireEmissary
我试着运行了asio自带的http例子,有调用async_read_until直到独到"\r\n\r\n"的,结果你懂的  回复  更多评论
  

# re: 恼人的boost::asio::async_read_until 2012-12-03 19:49 buy term papers
Nice effort, very informative, this will help me to complete my task.  回复  更多评论
  

# re: 恼人的boost::asio::async_read_until[未登录] 2012-12-05 00:06 Oliver
boost::asio::async_read_until(socket_,
stream_buffer_,
tail_regex_,
strand_.wrap(
boost::bind(&TCPClient::ReadHandler, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
async_read_until可以给出满足要求的数据长度,可传给读取函数,从buffer将指定长度的数据读取就可以了。
这样可以处理数据粘包。  回复  更多评论
  

# re: 恼人的boost::asio::async_read_until 2012-12-05 09:59 战魂小筑
@Oliver
正则表达式很High哦, 本来async_read_until就已经很费了
不过对于文本协议, 这也是一个好方法  回复  更多评论
  

# re: 恼人的boost::asio::async_read_until 2013-04-13 23:48 Adrian
人家是API嘛,又不是引擎- -!  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理