在上一篇博文中提到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. 使用jupyterthemes插件定制jupyter notebook界面

    jupyter notebook界面是可以定制的,定制位置在:C:\anaconda\Lib\site-packages\notebook\static\custom. 启动jupyter noteb ...

  2. Windows phone 应用开发系列教程(更新中)

    Windows phone 应用开发[1]-Text To Speech        作为开篇章节.第一篇将在如下介绍一些Windows phone比较有意思的东西-Text To Speech[文 ...

  3. Cordova+jQuery Mobile+Spring REST

    Cordova可以方便地建立跨平台的移动应用,使用jQuery Mobile做手机界面,后台使用rest提供数据交互. 首先,使用jQuery Mobile建立一个页面: <!DOCTYPE h ...

  4. MM bound 与 Jensen's inequality

    MM bound 与 Jensen's inequality 简森不等式 在使用最大似然估计方法求解模型最优解的时候,如果使用梯度下降(GD or SGD)或者梯度上升(GA or SGA),可能收敛 ...

  5. WCF Service中HttpContext.Current为null的解决办法

    1. 在hosting WCF的web.config中加入: <system.serviceModel> <serviceHostingEnvironment aspNetCompa ...

  6. PowerDesigner使用:[3]创建索引

    PowerDesigner是一款功能非常强大的建模工具软件,足以与Rose比肩,同样是当今最著名的建模软件之一.Rose是专攻UML对象模型的建模工具,之后才向数据库建模发展,而PowerDesign ...

  7. 【Java】解析Java对XML的操作

    目录结构: contents structure [+] 什么是XML 解析XML 使用DOM解析 使用SAX解析 使用PULL解析 使用dom4j解析xml dom4j的部分API 打印一个XML文 ...

  8. iOS 不支持 PWA,那又怎么样?

    原文链接http://www.zcfy.cc/article/ios-doesn-8217-t-support-progressive-web-apps-so-what-cloud-four-3400 ...

  9. iOS AFNetWorking下得Basic Auth认证请求方式

    我新入职了一家公司,做了一个项目,服务器的大哥说他采用的是Basic Auth认证请求方式,一般我们用的都是OAuth的认证方式,下面我们就对比一下这两种认证方式 百度百科得到如下 Basic Aut ...

  10. Android Studio找不到FragmentActivity类

    右击项目——>open module settings——>选择第五个选项卡“Dependencies”——>点击加号——>选择第一个Library dependency——& ...