Boost asio的async_write函数输入日志标题
2014-08-06 14:52
495 查看
Boost asio是一个异步网络通信的库,其中async_write是一个比较常用的函数,但是,如果没有正确的使用,就可能会出现一些意想不到的潜在Bug。例如下面的代码:
代码很简单,就是循环N次,发送N块buffer。我们的目标是,接收端依次接收buffer1,buffer2,……,buffer n。但是,事实上,上面的代码是有问题的,服务器可能会接收到完全错乱的数据。先看一下正确的写法,代码如下:
也就是在第一个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.
1: for (int i=0; i < n; i++)
2: {
3: boost::asio::async_write(
4: socket_,
5: boost::asio::buffer( buffer[i].data_.get(), buffer[i].length_ ),
6: boost::asio::transfer_at_least(buffer[i].length_),
7: boost::bind(
8: &HttpServer::HandleTcpSend,
9: shared_from_this(),
10: boost::asio::placeholders::error,
11: boost::asio::placeholders::bytes_transferred
12: )
13: );
14: // Do something
15: }
代码很简单,就是循环N次,发送N块buffer。我们的目标是,接收端依次接收buffer1,buffer2,……,buffer n。但是,事实上,上面的代码是有问题的,服务器可能会接收到完全错乱的数据。先看一下正确的写法,代码如下:
1: int i=0;
2: boost::asio::async_write(
3: socket_,
4: boost::asio::buffer( buffer[i].data_.get(), buffer[i].length_ ),
5: boost::asio::transfer_at_least(buffer[i].length_),
6: boost::bind(
7: &HttpServer::HandleTcpSend,
8: shared_from_this(),
9: boost::asio::placeholders::error,
10: boost::asio::placeholders::bytes_transferred
11: )
12: );
13:
14: // Do something
15:
16: void HttpServer::HandleTcpSend(const boost::system::error_code& err,
17: size_t bytes_transferred)
18: {
19: i++;
20: boost::asio::async_write(
21: socket_,
22: boost::asio::buffer( buffer[i].data_.get(), buffer[i].length_ ),
23: boost::asio::transfer_at_least(buffer[i].length_),
24: boost::bind(
25: &HttpServer::HandleTcpSend,
26: shared_from_this(),
27: boost::asio::placeholders::error,
28: boost::asio::placeholders::bytes_transferred
29: )
30: );
31: }
也就是在第一个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.
相关文章推荐
- 输入日志标题
- 输入日志标题
- 输入日志标题
- C++类的公用继承输入日志标题
- HTML4如何让一个DIV居中对齐?float输入日志标题
- Oracle 安装报错 [INS-06101] IP address of localhost could not be determined 解决方法输入日志标题
- HTML6注册表单输入日志标题
- 扒一扒各大电商网站的m站都用的什么前端技术输入日志标题
- Image Transformation in WPF输入日志标题
- 企业级开源邮箱EMOS1.5输入日志标题
- .NET日期格式化备忘输入日志标题
- 输入日志标题
- log4j多文件输入日志
- pyhton中的logging 输入到日志以及输出到文件
- VisualSVN 配置提交svn时强制输入日志
- 服务器logback输入的日志文件中文乱码问题
- adb logcat输入日志乱码
- java--IO流-LineNumberReader,读取键盘录入,字符字节流转换,改变标准输入输出设备,异常的日志信息,系统信息
- coolpad 5879logcat不能输入日志解决办法
- 日志钩子能分辨不同编辑控件中输入的字符吗?