今天在看boost库的时候注意到异步I/O操作时,缓冲区有效性问题。

如何实现异步操作:以异步读操作为例async_read(buffer, handler);

void handler() {}

void function()
{
char buffer[1234];
async_read(buffer, handler);
}
当运行function时会不会有安全隐患,因为这时候缓冲区buffer已经被释放了!
需要了解异步操作做了哪些事情,async_read会将回调函数handler注册到能够检测到i/o事件的地方,并将buffer的地址也传递过去,用于存放接收到的数据。
因此需要保证缓冲区buffer的有效性。
一个例子:(从网上找来的,具体出处没找到)

  1. #include <iostream>
  2. #include <string>
  3. #include <boost/asio.hpp>
  4. #include <boost/bind.hpp>
  5. #include <boost/smart_ptr.hpp>
  6. using namespace boost::asio;
  7. using boost::system::error_code;
  8. using ip::tcp;
  9. struct CHelloWorld_Service{
  10. CHelloWorld_Service(io_service &iosev)
  11. :m_iosev(iosev),m_acceptor(iosev, tcp::endpoint(tcp::v4(), 1000))
  12. {
  13. }
  14. void start()
  15. {
  16. // 开始等待连接(非阻塞)
  17. boost::shared_ptr<tcp::socket> psocket(new tcp::socket(m_iosev));
  18. // 触发的事件只有error_code参数,所以用boost::bind把socket绑定进去
  19. m_acceptor.async_accept(*psocket,
  20. boost::bind(&CHelloWorld_Service::accept_handler, this , psocket, _1)
  21. );
  22. }
  23. // 有客户端连接时accept_handler触发
  24. void accept_handler(boost::shared_ptr<tcp::socket> psocket, error_code ec)
  25. {
  26. if (ec) return ;
  27. // 继续等待连接
  28. start();
  29. // 显示远程IP
  30. std::cout << psocket->remote_endpoint().address() << std::endl;
  31. // 发送信息(非阻塞)
  32. boost::shared_ptr<std::string> pstr(new std::string( "hello async world!" ));
  33. psocket->async_write_some(buffer(*pstr),
  34. boost::bind(&CHelloWorld_Service::write_handler, this , pstr, _1, _2)
  35. );
  36. }
  37. // 异步写操作完成后write_handler触发
  38. void write_handler(boost::shared_ptr<std::string> pstr,
  39. error_code ec, size_t bytes_transferred)
  40. {
  41. if (ec)
  42. std::cout<< "发送失败!" << std::endl;
  43. else
  44. std::cout<< *pstr << " 已发送" << std::endl;
  45. }
  46. private :
  47. io_service &m_iosev;
  48. ip::tcp::acceptor m_acceptor;
  49. };
  50. int main( int argc, char * argv[])
  51. {
  52. io_service iosev;
  53. CHelloWorld_Service sev(iosev);
  54. // 开始等待连接
  55. sev.start();
  56. iosev.run();
  57. return 0;
  58. }

在这个例子中,首先调用sev.start() 开 始接受客户端连接。由于async_accept 调 用后立即返回,start() 方 法 也就马上完成了。sev.start()在 瞬间返回后iosev.run() 开 始执行,iosev.run()方法是一个循环,负责分发异步回调事件,只 有所有异步操作全部完成才会返回。

这里有个问题,就是要保证start()方法中m_acceptor.async_accept 操 作所用的tcp::socket 对 象 在整个异步操作期间保持有效 (不 然系统底层异步操作了一半突然发现tcp::socket没了,不是拿人家开涮嘛-_-!!!),而且客户端连接进来后这个tcp::socket对象还 有用呢。这里的解决办法是使用一个带计数的智能指针boost::shared_ptr<tcp:: socket> ,并把这个指针作为参数绑定到回调函数上。

一旦有客户连接,我们在start()里给的回调函数accept_handler 就会被 调用,首先调用start()继续异步等待其 它客户端的连接,然后使用绑定进来的tcp::socket对象与当前客户端通信。

发送数据也使用了异步方式(async_write_some ), 同样要保证在整个异步发送期间缓冲区的有效性,所以也用boost::bind绑定了boost::shared_ptr<std:: string>。

异步I/O操作的更多相关文章

  1. 【原创-算法-实现】异步HTTP请求操作

    一.说明 1) 这个类 是我 在真实项目中,优化解决真实问题 时,不参考第三方代码,完全由自己查阅MSDN官方文档 , 完成的一个真实生产环境中使用的功能类 2) 读者在使用此类时,请尊重原创,在代码 ...

  2. Task:取消异步计算限制操作 & 捕获任务中的异常

    Why:ThreadPool没有内建机制标记当前线程在什么时候完成,也没有机制在操作完成时获得返回值,因而推出了Task,更精确的管理异步线程. How:通过构造方法的参数TaskCreationOp ...

  3. IOS异步和多线程操作&&在sqlite3中的应用

    1,数据库I/O操作(异步) 数据库本身是存储在磁盘上.访问和修改数据库,即对磁盘进行读写,即I/O操作. 磁盘属于计算机硬件,具有DMA能力,不需要CPU干预,可以实现异步操作. I/O操作一般是消 ...

  4. asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案

    之前碰到asp.net core异步进行新增操作并且需要判断某些字段是否重复的问题,进行插入操作的话会导致数据库中插入重复的字段!下面把我的解决方法记录一下,如果对您有所帮助,欢迎拍砖! 场景:EFC ...

  5. C# Windows异步I/O操作

    1.简介 关于Windows的异步I/O操作,只要解决的是同步I/O操作的线程利用率问题,通过异步I/O Api来提升线程的利用率,提升系统的吞吐能力,将各种I/O操作交给线程池然后交由硬件设备执行, ...

  6. C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志

    C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...

  7. RabbitMQ实战场景(一):异步记录用户操作日志

    传统的项目开发中业务流程以串行方式,执行了模块1—>模块2–>模块3 而我们知道,这个执行流程其实对于整个程序来讲是有一定的弊端的,主要有几点: (1)整个流程的执行响应等待时间比较长; ...

  8. mvc file控件无刷新异步上传操作

    前言 上传文件应该是很常见必不可少的一个操作,网上也有很多提供的上传控件.今天遇到一个问题:input控件file无法进行异步无刷新上传.真真的感到别扭.所以就尝试这去处理了一下.主要分三个部分:上传 ...

  9. 进程理论 阻塞非阻塞 同步异步 I/O操作

    1.什么是进程 进程指的是一个正在运行的程序,进程是用来描述程序执行过程的虚拟概念 进程的概念起源于操作系统,进程是操作系统最核心的概念,操作系统其它所有的概念都是围绕进程来的 2.操作系统 操作系统 ...

随机推荐

  1. PAT 02-线性结构1 两个有序链表序列的合并 (15分)

    本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个递增的整数序列. 函数接口定义: List Merge( List L1, List L2 ); 其中List结构定义如下: typedef ...

  2. .NET (二)委托第二讲:内置委托Func

    在上一章节中,我们自己声明了一个委托: public delegate bool Cal(int num); 接受int参数,返回bool类型,目的是过滤集合中的 奇数 或者 偶数. .NET 为我们 ...

  3. js闭包,匿名函数概念

    var functionName = function(arg){ //函数体 }; 匿名函数:创建一个函数,并将它赋值给一个变量,这种情况下创建的函数叫做匿名函数,因为function关键字后面没有 ...

  4. asp.net MVC上传图片完整方法

    图片上传 自动创建文件夹并重命名(带缩略图) 后台: [HttpPost] public ActionResult WanSell_UploadPicture(ProductGalleryModels ...

  5. 转 Jmeter之Bean shell使用(一)

    一.什么是Bean Shell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法; BeanShell是一种松散类型的脚本语言(这点和JS类似); BeanS ...

  6. Mathematica(MMA)闪电入门系列 目录与说明

    Mathematica(MMA)闪电入门系列  入口 本文起到目录作用,点击以下链接,可以打开各章: 一.MMA概述二.表操作三.函数与递归四.表达式的计算五.过程式编程和调试技巧六.图形七.程序包 ...

  7. javascript-binarySearch

    前提: 数组已排序,且为正整数数组. function brnarySearch(arg, arr) { var right = arr.length - 1; var left = 0; while ...

  8. MySQL5.6:基于GTID的主从复制

    一.GTID简介 MySQL 5.6 的新特性之一,是加入了全局事务 ID (GTID) 来强化数据库的主备一致性,故障恢复,以及容错能力. 什么是GTID? 官方文档:http://dev.mysq ...

  9. 【原】如何在jQuery中实现闭包

    原生JS中,闭包虽好用,但是很难用好,在jQuery中一样,都有一些点需要我们注意.jQuery中使用闭包的常见情况有以下几种: 1.$(document).ready()的参数 我们在写jQuery ...

  10. MFC 不让程序显示在任务栏上

    如果是对话框程序直接在对话框的 初始化时,修改样式 ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW); 但是对于多文档或是单文档,则没有对应的对话框样式需 ...