在实际产品运行中,对连接管理有了更新的认识,这里分享一下。

shared_ptr管理连接对象的生命周期

shared_ptr的引用计数器决定了连接对象的生命周期。这里我说的连接对象就是在我的前文:http://blog.csdn.net/csfreebird/article/details/8522620

中的Client对象:

  1. #include "core/connection.h"
  2. #include <vector>
  3. using namespace std;
  4. class Client: public Connection<Client> {
  5. public:
  6. Client(io_service& s);

销毁连接对象的条件

那么什么情况下shared_ptr的引用技术会变成0呢?必须满足下列所有条件:

1. 如果你不再发起任何异步读/写操作

因为每一次异步读/写操作都会将Client对象自己的this指针包装成shared_ptr,通过bind交给boost asio框架,此时框架将持有该shared_ptr,直到读/写完成,回调我们自己的函数后才会将引用计数器减1。

2. 如果没有任何其他对象或者容器持有这个shared_ptr。

实际通信程序为了实现服务器事件通知,我会将所有的Client对象的shared_ptr保存在一个容器中,比如map。然后定期的检查这些Client有没有在数据库中有事件要发布,如果有,则调用Client的方法发送数据。也会定期检查Client对象代表的连接上的心跳消息,如果心跳超时,则将share_ptr从map中移除掉,并停止任何读/写的异步操作(也就是上上面第一个条件)

只有在满足了这两个条件的情况下,shared_ptr会自动销毁Client对象,Client对象内部的成员变量socket也会被销毁。

一般情况下不需要手动关闭socket

所以,我之前用下面的函数关闭socket一般情况下是不需要的

  1. void CloseSocket() {
  2. try {
  3. socket.shutdown(tcp::socket::shutdown_both);
  4. socket.close();
  5. } catch (std::exception& e) {
  6. BOOSTER_INFO("Connection") << "thread id: " << this_thread::get_id() << e.what() << endl;
  7. }
  8. }

多线程环境下关闭连接导致crash

如果要使用CloseSocket,多线程环境下必须小心。比如我碰到过这样的情况:一个线程检查到了超时,然后调用Client::CloseSocket方法,同时另一个线程正在该Client上发起了异步的读/写操作,结果进程崩溃了。boost asio不允许这样做。

参考:http://web.archiveorange.com/archive/v/Q0J4VefPMc2v8QYvcVr3

异步读/写阻塞导致连接对象无法销毁

如果就坚持不用CloseSocket行么,我碰到另一种情况,async_write/async_read会阻塞,结果shared_ptr的引用计数不会为0,所以Client对象无法被销毁。那么怎么安全的调用CloseSocket的呢?用strand,下面是代码:

  1. void Client::ToClose() {
  2. strand_.post(bind(&Client::DoClose, shared_from_this()));
  3. }
  4. void Client::DoClose() {
  5. CloseSocket();
  6. }

其他线程就只需要调用ToClose函数即可。
由于strand_.post的桥梁作用,CloseSocket会在io_service运行的线程池中被保护。就不会出现和async_read/async_write同时被执行的情况。

在实际编程中我们可能由于很多原因要关闭连接,比如前面说的心跳超时,也有收到了不正确的数据,或者在asio传递出来的网络错误,又或者是收到了关闭进程的信号。

无论何种原因,都可以采用上面的方式进行关闭连接。所以原则只有一个,记住shared_ptr的生命周期即可。

优雅的关闭进程

如何在这种情况下优雅的退出进程是个问题,否则退出时程序会crash,留下core文件。这种情况是:

1. 线程池中运行这io_service对象,进行异步的读/写操作

2. 一个线程定期检查数据库中的事件消息,并发送给所有远程终端,同时检查每个连接的心跳超时时间。

3. 一个全局的map对象保存了所有Client的shared_ptr。

在以后的文章中会探索。

boost::asio 连接管理11 如何关闭连接的更多相关文章

  1. TCP系列04—连接管理—3、TCP连接的半打开和半关闭

    在前面部分我们我们分别介绍了三次握手.四次挥手.同时打开和同时关闭,TCP连接还有两种场景分别是半打开(Half-Open)连接和半关闭(Half-Close)连接.TCP是一个全双工(Full-Du ...

  2. TCP系列03—连接管理—2、TCP连接的同时打开和同时关闭

    在前面的内容中我们介绍了TCP连接管理中最常见的三次握手方式和四次挥手的方式.但是有可能A和B两端同时执行主动打开并连接对方或者同时执行主动关闭连接(尽管发生这种情况的可能性比较低低),这个时候的流程 ...

  3. TCP系列07—连接管理—6、TCP连接管理的状态机

            经过前面对TCP连接管理的介绍,我们本小节通过TCP连接管理的状态机来总结一下看看TCP连接的状态变化 一.TCP状态机整体状态转换图(截取自第二版TCPIP详解) 二.TCP连接建立 ...

  4. TCP系列05—连接管理—4、TCP连接的ISN、连接建立超时及TCP的长短连接

    一.TCP连接的ISN         之前我们说过初始建立TCP连接的时候的系列号(ISN)是随机选择的,那么这个系列号为什么不采用一个固定的值呢?主要有两方面的原因 防止同一个连接的不同实例(di ...

  5. HTTP协议建立连接、通讯与关闭连接全过程

    为解决服务器TimeWait多的问题,了解了一下TCP/IP协议的连接过程.以访问一静态页面为例,从建立连接到访问拿到数据,然后关闭的整个过程.使用EtherPeek截图如下:   图首为一次交互过程 ...

  6. 基于java 的websocket的聊天功能,一开始初始化websocket,执行打开连接之后就直接关闭连接了。

    1 错误描述: java 后台没有报错,但是就是连接不上,一连上又自动关闭. 2 错误根源: 缺少jar包. 对比了报错的tomcat 的jar包和不报错的jar包 发现是tomcat下缺少上图绿色框 ...

  7. 前端学HTTP之连接管理

    前面的话 HTTP连接是HTTP报文传输的关键通道.要掌握HTTP就需要理解HTTP连接的来龙去脉以及如何使用这些连接 如果想查看一个网页,浏览器收到URL时,会执行下图所示的步骤.将服务器的IP地址 ...

  8. Mybatis 打开连接池和关闭连接池性能对比

    1  创建数据库表 -- phpMyAdmin SQL Dump -- version 4.2.11 -- http://www.phpmyadmin.net -- -- Host: localhos ...

  9. Netty中的连接管理

    连接管理是我们首先需要关注的,检测空闲连接以及超时对于及时释放资源来说是至关重要的.由于这是一项常见的任务,Netty特地为它提供了几个ChannelHandler实现. 用于空闲连接以及超时的Cha ...

随机推荐

  1. Yii Framework2.0开发教程(2)使用表单Form

    第一步.接着教程(1).我们在controllers/ZhyoulunController.php中加入两处, 1) use app\models\EntryForm; 和 2) public fun ...

  2. HDU 3060 多边形面积并

    Area2 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  3. onmouseover和onmouseout的烦恼

    一个DIV层,当鼠标移进的时候会触发onmouseover,移出的时候会触发onmouseout.   非常easy的逻辑,这也是我们想要的!但随之烦恼也就来了:onmouseover并不会仅仅在移进 ...

  4. JAVA 软件升级版本号比较

    简单版本号比较: public class CompareVersion {   public static void main(String[] args) { // TODO Auto-gener ...

  5. ASP.NET MVC 5 学习教程:修改视图和布局页

    原文 ASP.NET MVC 5 学习教程:修改视图和布局页 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 ...

  6. PLSQL Developer使用技巧整理(转)

    一.工具-首选项-用户界面-编辑器-其它-显示行号二.工具-首选项-窗口类型-SQL窗口-显示隔号(行号) 在使用PL/SQL Developer对Procedure进行Debug时,突然发现无法Se ...

  7. smarty 截取字符串,调用php中的方法,foreach循环

    1.smarty截取字符串       html中的代码    <{$content|truncate:30:"..."}>                       ...

  8. Hadoop实战实例

    Hadoop实战实例        Hadoop实战实例        Hadoop 是Google MapReduce的一个Java实现.MapReduce是一种简化的分布式编程模式,让程序自动分布 ...

  9. UNIX环境高级编程——进程管理和通信(总结)

    进程管理与通信 进程的管理 进程和程序的区别: 进程: 程序的一次执行过程   动态过程,进程的状态属性会发生变化 程序:存放在磁盘上的指令.数据的有序集合  是个文件,可直观看到 程序program ...

  10. 中科燕园GIS外包---地铁GIS项目

    (1)地铁保护及project地质管理     • 地铁保护     地铁交通既有运量大,速度快的特点,又有差别于其它交通方式的在地下执行的空间特殊性,因此地铁的保护显得尤为重要. 首先必须编制完整的 ...