恼人的boost::asio::async_read_until

恼人的boost::asio::async_read_until
2012-12-04 10:09:51      我来说两句      
收藏    我要投稿

最近为服务器添加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构造时加一个最大一个读取量, 超过此量会返回报错, 避免了缓冲区被撑爆的危险

 http://www.cppblog.com/sunicdavy/archive/2012/12/03/195921.html

http://www.boost.org/doc/libs/1_43_0/doc/html/boost_asio/reference/async_read_until/overload1.html 

`boost::asio::async_read_until` 是 Boost.Asio 库中的一个异步读取函数,用于从网络或其他流中读取数据直到遇到某个特定的终止符。如果想要停止并退出异步操作,通常会在回调函数中处理中断信号或者满足某个条件。 以下是一个基本的示例,展示了如何在 `async_read_until` 的完成事件处理器中控制退出: ```cpp #include <boost/asio.hpp> using boost::asio::ip::tcp; using boost::asio::streambuf; std::string terminator = "\r\n"; // 假设我们正在等待换行符作为结束标记 void read_handler(const boost::system::error_code& error, std::size_t bytes_transferred, boost::asio::streambuf& sb) { if (!error) { // 如果没有错误 std::string data(reinterpret_cast<const char*>(sb.data()), bytes_transferred); // 检查数据是否到达预期的终止符 if (data.rfind(terminator) != std::string::npos) { // 数据已完整读取,处理数据后可以停止操作 do_something_with_data(data); stop_async_operation(); // 假设有一个函数用于停止异步操作 } else { // 继续读取,直到找到终止符 boost::asio::async_read_until(socket_, sb, terminator, read_handler); } } else { // 错误发生,处理错误后可能需要退出 handle_error(error); } } int main() { tcp::socket socket(io_service); // 开始连接和建立流... boost::asio::async_read_until(socket, sb, terminator, read_handler); // 开始异步读取 io_service.run(); // 运行服务直至所有任务完成或被stop_async_operation()中断 return 0; } ``` 在这个例子中,当你希望停止读取时,可以在读取完成后的条件检查中调用 `stop_async_operation()`,这可能会关闭套接字或者设置一个标志通知主循环不再继续处理此任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值