加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Boost asio的async_write函数

(2012-07-31 15:11:32)
标签:

杂谈

分类: boost
Boost asio是一个异步网络通信的库,其中async_write是一个比较常用的函数,但是,如果没有正确的使用,就可能会出现一些意想不到的潜在Bug。例如下面的代码:


for (int i=0; i < n; i++)
{
    boost::asio::async_write(
        socket_,
        boost::asio::buffer( buffer[i].data_.get(), buffer[i].length_ ),
        boost::asio::transfer_at_least(buffer[i].length_),
        boost::bind(
            &HttpServer::HandleTcpSend,
            shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred         
        )
    );
    // Do something
}
代码很简单,就是循环N次,发送N块buffer。我们的目标是,接收端依次接收buffer1,buffer2,……,buffer n。但是,事实上,上面的代码是有问题的,服务器可能会接收到完全错乱的数据。先看一下正确的写法,代码如下:


    int i=0;
    boost::asio::async_write(
        socket_,
        boost::asio::buffer( buffer[i].data_.get(), buffer[i].length_ ),
        boost::asio::transfer_at_least(buffer[i].length_),
        boost::bind( 
            &HttpServer::HandleTcpSend, 
            shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred         
        )
    );
 
    // Do something
 
void HttpServer::HandleTcpSend(const boost::system::error_code& err, 
    size_t bytes_transferred)
{
    i++;
    boost::asio::async_write(
        socket_,
        boost::asio::buffer( buffer[i].data_.get(), buffer[i].length_ ),
        boost::asio::transfer_at_least(buffer[i].length_),
        boost::bind( 
            &HttpServer::HandleTcpSend, 
            shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred         
        )
    );
}
也就是在第一个buffer发成功之后,再发送第二个buffer,依次类推。为什么一定要这样写呢?首先,看一下async_write是怎么实现的,aysnc_write里面调用async_write_some函数。也就是说,async_write一次数据发送,并一定把所有的数据都发送完,有可能async_write一次就发其中的一部分。那么,如果在第一个async_write还没有发送完毕之后,从第二个async_write发送数据,势必导致接收端接收的数据有问题。这个并不是asio的限制,底层套接字的一些函数,如发送等也无法保证一次异步操作就把所有的数据都通过TCP流发送出去。async_write将被告知有多少字节实际发送了,然后要求在下一次异步操作时发送剩余的字节。async_write是通过一次或者多次调用async_write_some函数来实现的,那么如果在第一个async_write还没有完成就调用第二个async_write,async_write_some就有可能先将第二个buffer的数据先发送出去。

因此,NEVER start your second async_write before the first has completed.

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有