(原创)谈谈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来说是非常重要的. 为什么须要异步 如前所述,通常同步编程要比异步编程更简单.同步 ...
随机推荐
- jquery.uploadify 在firefox会出现httperror
原来是因为我的上传处理页面的page 继承了一个基类影响到的 然后这个基类 好像是因为在别的项目里面的原因 希望对也遇到这样的问题的人有帮助咯
- 【LeetCode】Longest Substring with At Most Two Distinct Characters (2 solutions)
Longest Substring with At Most Two Distinct Characters Given a string, find the length of the longes ...
- MYSQL IN 与 EXISTS 的优化示例介绍
优化原则:小表驱动大表,即小的数据集驱动大的数据集. ############# 原理 (RBO) ##################### select * from A where id in ...
- Linux IO系统分析(scsi篇)
一.概述 Linux内核中SCSI子系统由SCSI上层,中间层,底层驱动模块三部分组成,负责管理SCSI资源和处理其他子系统,如文件系统,提交到SCSI子系统中的IO请求. 因此,理解SCSI子系统的 ...
- 【Oracle】详解Oracle中的序列
序列: 是oacle提供的用于产生一系列唯一数字的数据库对象. 自动提供唯一的数值 共享对象 主要用于提供主键值 将序列值装入内存可以提高访问效率 创建序列: 1. 要有创建序列的权限 create ...
- 【colaboratory】在colab中安装mxnet
在学习<动手学深度学习>内容是,该内容用的是mxnet框架,在电脑本地安装过程中又容易出现错误,怎么也安装不上,所有的条件都尝试了. 汗颜,指的另谋他法. 只有在谷歌的学习平台上安装使用h ...
- mysqld Can’t start server : Bind on unix socket: Permission denied
启动mysql报错: mysqld Can’t start server : Bind on unix socket: Permission denied 原因: mysql.sock无法建立,权限问 ...
- SQL Server 阻止了对组件 'Agent XPs' 的 过程 'dbo.sp_set_sqlagent_properties' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。
Sqlserver 2008 在配置分发向导的时候报了如下错误: 使用 Agent XPs 选项可以启用此服务器上的 SQL Server 代理扩展存储过程.如果禁用此选项,则 SQL Server ...
- Java Nashorn--Part 5
Nashorn 的高级应用 Nashorn 是一个复杂的编程环境,它被设计为一个强大的平台,用于部署应用程序,并与Java具有极大的互操作性. 让我们来看一些更高级的用于 JavaScript 到 J ...
- Java读取excel的示例
一.引用的jar包,apache的POI // https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml compile group: ' ...