在上一篇博文中提到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重新发起异步循环发送。

  可以看到,异步发送比异步接收等其他异步操作更复杂,需要一个发送队列来保证发送不会乱序。但是,还有一个问题需要注意就是这个发送队列是没有加限制的,如果接收端收到数据之后阻塞处理,而发送又很快的话,就会导致发送队列的内存快速增长甚至内存爆掉。解决办法有两个:

  1. 发慢一点,并且保证接收端不会长时间阻塞socket;
  2. 控制发送队列的上限。

  第一种方法对实际应用的约束性较强,实际可操作性不高。第二种方法需要控制队列上限,不可避免的要加锁,这样就丧失了单线程异步发送的性能优势。所以建议用同步发送接口来发送数据,一来不用发送队列,自然也不会有内存暴涨的问题,二来也不会有复杂的循环发送过程,而且还可以通过线程池来提高发送效率。

总结:

  • 不要连续发起异步发送,要等上次发送完成之后再发起下一个异步发送;
  • 要考虑异步发送的发送队列内存可能会暴涨的问题;
  • 相比复杂的异步发送,同步发送简单可靠,推荐优先使用同步发送接口。

如果你觉得这篇文章对你有用,可以点一下推荐,谢谢。

c++11 boost技术交流群:296561497,欢迎大家来交流技术。

(原创)谈谈boost.asio的异步发送的更多相关文章

  1. boost::asio 同步&异步例子

    同步客户端: using boost::asio; io_service service; ip::tcp::endpoint ep( ip::address::from_string(); ip:: ...

  2. 使用Boost asio实现异步的TCP/IP通信

    可以先了解一下Boost asio基本概念,以下是Boost asio实现的异步TCP/IP通信: 服务器: #include "stdafx.h" #include <io ...

  3. boost Asio网络编程简介

    :first-child { margin-top: 0px; } .markdown-preview:not([data-use-github-style]) h1, .markdown-previ ...

  4. Boost.Asio的使用技巧

    基本概念 Asio proactor I/O服务 work类 run() vs poll() stop() post() vs dispatch() buffer类 缓冲区管理 I/O对象 socke ...

  5. boost.asio源码剖析(三) ---- 流程分析

    * 常见流程分析之一(Tcp异步连接) 我们用一个简单的demo分析Tcp异步连接的流程: #include <iostream> #include <boost/asio.hpp& ...

  6. Boost Asio介绍--之一

    原文:http://www.tuicool.com/articles/YbeYR3 Boost Asio介绍--之一 时间 2014-03-26 17:57:39  CSDN博客 原文  http:/ ...

  7. Boost Asio(一)初探

    一.简介 Boost Asio ( asynchronous input and output)关注数据的异步输入输出.Boost Asio 库提供了平台无关性的异步数据处理能力(当然它也支持同步数据 ...

  8. boost::asio 的同、异步方式

    转自:http://blog.csdn.net/zhuky/archive/2010/03/10/5364574.aspx Boost.Asio是一个跨平台的网络及底层IO的C++编程库,它使用现代C ...

  9. Boost.Asio基础(五) 异步编程初探

    异步编程 本节深入讨论异步编程将遇到的若干问题.建议多次阅读,以便吃透这一节的内容,这一节是对整个boost.asio来说是非常重要的. 为什么须要异步 如前所述,通常同步编程要比异步编程更简单.同步 ...

随机推荐

  1. Screen2EXE录屏|录制视频

    Screen2EXE是一款具有独到压缩算法的屏幕录制软件,它可以记录用户在屏幕上的每一步操作,包括鼠标轨迹,点击动作给予花环提示,然后保存为不需播放器即可观看的exe可执行文件. 在生成录制文件的大小 ...

  2. TL 重构

    import dependencies.*;import org.apache.commons.lang3.ArrayUtils;import org.apache.commons.lang3.Str ...

  3. 类型“System.Data.SQLite.SQLiteParameter”在未被引用的程序集中定义。必须添加对程序集“System.Data.SQLite, Version=1.0.66.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139”的引用

    出现这个问题是 你的系统是64位 同时 dll生成的 any cpu 应该换为 x86

  4. SqlServer安装时的选项说明

    转自:https://blog.csdn.net/m0_37154839/article/details/80233446 看看组件的功能说明吧 服务器组件 说明 SQL Server 数据库引擎 S ...

  5. windows修改环境变量

    windows的环境变量有两套: 系统的 当前用户的 不同的用户可以拥有不同的环境变量,当前用户的环境变量优先级比系统的环境变量优先级高,PATH环境变量比较特殊,它不是替换而是拼接. 在命令行下也可 ...

  6. 第一次使用Mac

    Mac禁用掉默认输入法 搜狗输入法已经包含中文.英文输入法了,其余输入法可以删除掉.按ctrol键的时候本来应该是搜狗输入法中英文切换,结果却是搜狗输入法和ABC输入法之间互相切换. 打开键盘偏好设置 ...

  7. OC中instancetype与id的区别

    1.在ARC环境下: instancetype用来在编译期确定实例的类型,而使用id的话,编译器不检查类型, 运行时检查类型. 2.在MRC环境下: instancetype和id一样,不做具体类型检 ...

  8. Win7 U盘安装Ubuntu16.04 双系统详细教程(方法一)

    主要分为以下几步: 一. 下载Ubuntu 16.04镜像软件: 二. 制作U盘启动盘使用ultraISO: 三. 安装Ubuntu系统: 四. 用EasyBCD 创建启动系统启动引导: (根据个人情 ...

  9. Fedora下使用minicom及USB串口线

    一.minicom Fedora不像以前的RedHat,不能直接输入minicom回车,因为在目录/dev/下面没有modem这个子目录,而minicom的运行默认是有这个目录的,所以直接敲是不行的. ...

  10. socket编程及API简介

    什么是TCP/IP.UDP? TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域 ...