(原创)谈谈boost.asio的异步发送
在上一篇博文中提到asio的异步发送稍微复杂一点,有必要单独拿出来说说。asio异步发送复杂的地方在于: 不能连续调用异步发送接口async_write,因为async_write内部是不断调用async_write_some,直到所有的数据发送完成为止。由于async_write调用之后就直接返回了,如果第一次调用async_write发送一个较大的包时,马上又再调用async_write发送一个很小的包时,有可能这时第一次的async_write还在循环调用async_write_some发送,而第二次的async_write要发送的数据很小,一下子就发出去了,这使得第一次发送的数据和第二次发送的数据交织在一起了,导致发送乱序的问题。解决这个问题的方法就是在第一次发送完成之后再发送第二次的数据。具体的做法是用一个发送缓冲区,在异步发送完成之后从缓冲区再取下一个数据包发送。下面看看异步发送的代码是如何实现的。
list<MyMessage> m_sendQueue; //发送队列 void HandleAsyncWrite(char* data, int len)
{
bool write_in_progress = !m_sendQueue.empty();
m_sendQueue.emplace_back(data, len);
if (!write_in_progress)
{
AsyncWrite();
}
} void AsyncWrite()
{
auto msg = m_sendQueue.front();
async_write(m_sock, buffer(msg.pData, msg.len),
[this](const boost::system::error_code& ec, std::size_t size)
{
if (!ec)
{
m_sendQueue.pop_front(); if (!m_sendQueue.empty())
{
AsyncWrite();
}
}
else
{
HandleError(ec);
if (!m_sendQueue.empty())
m_sendQueue.clear();
}
});
}
代码的逻辑是这样的:当用户发送数据时,不直接调用异步发送接口,而是将数据放到一个发送队列中,异步发送接口会循环从队列中取数据发送。循环发送过程的一个细节需要注意,用户发送数据时,如果发送队列为空时,说明异步发送已经将队列中所有的数据都发送完了,也意味着循环发送结束了,这时,需要在数据入队列之后再调用一下async_write重新发起异步循环发送。
可以看到,异步发送比异步接收等其他异步操作更复杂,需要一个发送队列来保证发送不会乱序。但是,还有一个问题需要注意就是这个发送队列是没有加限制的,如果接收端收到数据之后阻塞处理,而发送又很快的话,就会导致发送队列的内存快速增长甚至内存爆掉。解决办法有两个:
- 发慢一点,并且保证接收端不会长时间阻塞socket;
- 控制发送队列的上限。
第一种方法对实际应用的约束性较强,实际可操作性不高。第二种方法需要控制队列上限,不可避免的要加锁,这样就丧失了单线程异步发送的性能优势。所以建议用同步发送接口来发送数据,一来不用发送队列,自然也不会有内存暴涨的问题,二来也不会有复杂的循环发送过程,而且还可以通过线程池来提高发送效率。
总结:
- 不要连续发起异步发送,要等上次发送完成之后再发起下一个异步发送;
- 要考虑异步发送的发送队列内存可能会暴涨的问题;
- 相比复杂的异步发送,同步发送简单可靠,推荐优先使用同步发送接口。
如果你觉得这篇文章对你有用,可以点一下推荐,谢谢。
c++11 boost技术交流群:296561497,欢迎大家来交流技术。
(原创)谈谈boost.asio的异步发送的更多相关文章
- boost::asio 同步&异步例子
同步客户端: using boost::asio; io_service service; ip::tcp::endpoint ep( ip::address::from_string(); ip:: ...
- 使用Boost asio实现异步的TCP/IP通信
可以先了解一下Boost asio基本概念,以下是Boost asio实现的异步TCP/IP通信: 服务器: #include "stdafx.h" #include <io ...
- boost Asio网络编程简介
:first-child { margin-top: 0px; } .markdown-preview:not([data-use-github-style]) h1, .markdown-previ ...
- Boost.Asio的使用技巧
基本概念 Asio proactor I/O服务 work类 run() vs poll() stop() post() vs dispatch() buffer类 缓冲区管理 I/O对象 socke ...
- boost.asio源码剖析(三) ---- 流程分析
* 常见流程分析之一(Tcp异步连接) 我们用一个简单的demo分析Tcp异步连接的流程: #include <iostream> #include <boost/asio.hpp& ...
- Boost Asio介绍--之一
原文:http://www.tuicool.com/articles/YbeYR3 Boost Asio介绍--之一 时间 2014-03-26 17:57:39 CSDN博客 原文 http:/ ...
- Boost Asio(一)初探
一.简介 Boost Asio ( asynchronous input and output)关注数据的异步输入输出.Boost Asio 库提供了平台无关性的异步数据处理能力(当然它也支持同步数据 ...
- boost::asio 的同、异步方式
转自:http://blog.csdn.net/zhuky/archive/2010/03/10/5364574.aspx Boost.Asio是一个跨平台的网络及底层IO的C++编程库,它使用现代C ...
- Boost.Asio基础(五) 异步编程初探
异步编程 本节深入讨论异步编程将遇到的若干问题.建议多次阅读,以便吃透这一节的内容,这一节是对整个boost.asio来说是非常重要的. 为什么须要异步 如前所述,通常同步编程要比异步编程更简单.同步 ...
随机推荐
- ntp时钟同步
服务器时间的一致性,很关键的. 11. 基于ntp服务的形式 [root@server0 ~]# yum -y install chrony //NTP客户端 centos7.x cent ...
- LLVM和clang
LLVM编译器架构 LLVM项目是一套工具的集合,它包括模块化.可复用的编译器及一些列工具链技术. LLVM最开始是Low Level Virtual Machine的简称,但现在它并不是传统意义上的 ...
- 安装好php后找不到php.ini
很多同学在安装完php后找不到php.ini而烦恼. 通常php.ini的位置在: /etc目录下或/usr/local/lib目录下. 如果你还是找不到php.ini或者找到了php.ini修改后不 ...
- java 实现二分法
http://www.cnblogs.com/vanezkw/archive/2012/06/29/2569470.html JDK里面的二分法实现.二分法的实现有多种今天就给大家分享两种.一种是递归 ...
- 使用 WM_COPYDATA 在进程间共享数据
开发中有时需要进程间传递数据,比如对于只允许单实例运行的程序,当已有实例运行时,再次打开程序,可能需要向当前运行的实例传递信息进行特殊处理.对于传递少量数据的情况,最简单的就是用SendMessage ...
- 问题 “No mapping found for HTTP request with URI [/fileupload/upload.do]” 的解决
是因为自己springmvc的配置文件里面不小心删除掉了 <!-- 注解扫描 扫描该包下的注解--> <context:component-scan base-package=&qu ...
- Android之listview运用(美团美食列表)
首先我们将listview简单实现,有图形,有文字:效果如图 之前我们完成了一个较为简单的listview视图列表,但是生活中我们往往碰到的 是更为复杂列表,有图像有评分标准,不如我们来试一试手,做一 ...
- 启动mysql报错 -- ERROR! The server quit without updating PID file
开发说某个测试环境的mysql,无法重启了,报以下错误提示: # service mysqld restart Shutting down MySQL.. SUCCESS! Starting MySQ ...
- (LeetCode)用两个栈实现一个队列
LeetCode上面的一道题目.原文例如以下: Implement the following operations of a queue using stacks. push(x) -- Push ...
- stm8时钟
为使系统快速启动,复位后时钟控制器自动使用HSI的8分频(HSI/8)做为主时钟(2M).其原因为HSI的稳定时间短,而8分频可保证系统在较差的VDD条件下安全启动.一旦主时钟源稳定,用户程序可将主时 ...