boost::asio 连接管理11 如何关闭连接

简介: 在实际产品运行中,对连接管理有了更新的认识,这里分享一下。 shared_ptr管理连接对象的生命周期 shared_ptr的引用计数器决定了连接对象的生命周期。这里我说的连接对象就是在我的前文:http://blog.

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

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

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

中的Client对象:

 

[cpp]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
 
  1. #include "core/connection.h"  
  2. #include   
  3.   
  4. using namespace std;  
  5.   
  6. class Client: public Connection {  
  7.  public:  
  8.   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一般情况下是不需要的

 

[cpp]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
 
  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不允许这样做。 <

 

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

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

 

[cpp]  view plain copy print ?
 
  1. void Client::ToClose() {  
  2.   strand_.post(bind(&Client::DoClose, shared_from_this()));  
  3. }  
  4.   
  5. void Client::DoClose() {  
  6.   CloseSocket();  
  7. }  

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

 

 

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

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

 

优雅的关闭进程

 

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

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

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

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

在以后的文章中会探索。

目录
相关文章
|
4月前
|
缓存 网络协议 算法
提高服务端性能的几个socket选项
提高服务端性能的几个socket选项
140 3
|
网络协议 Linux C++
Linux TCP作为服务器连接的单连接、Select、Poll和Epoll方式:C/C++实现高效的服务器通信
在Linux服务器开发中,TCP(Transmission Control Protocol)作为面向连接的通信方式,为实现可靠的服务器通信提供了强大支持。不同的服务器连接方式,如单连接、Select、Poll和Epoll,各有优势,可以根据连接数和性能需求选择合适的方式。本文将深入探讨这四种方式的实现原理,并给出C/C++代码例子,帮助读者更好地理解和使用这些方式。
336 0
|
Python
x64dbg 实现插件Socket反向通信
编写一个带有socket通信功能的插件,x64dbg运行后,用户点击链接按钮可直接连接到外部的python中,python作为服务端,当x64dbg内部出现某个事件后,自动将消息推送到外部python脚本上,实现反向传参的目的。
182 0
x64dbg 实现插件Socket反向通信
|
网络协议 数据格式 JSON
使用boost::asio库实现多个子进程监听同一个端口
class session_http { public: session_http(boost::asio::io_context &io) : socket_(io) {}; void run(boost::asi...
2399 0
|
网络协议 Windows
通用异步 Windows Socket TCP 客户端组件的设计与实现
编写 Windows Socket TCP 客户端其实并不困难,Windows 提供了6种 I/O 通信模型供大家选择。但本座看过很多客户端程序都把 Socket 通信和业务逻辑混在一起,剪不断理还乱。
1090 0
|
缓存 网络协议 Windows
基于 IOCP 的通用异步 Windows Socket TCP 高性能服务端组件的设计与实现
设计概述   服务端通信组件的设计是一项非常严谨的工作,其中性能、伸缩性和稳定性是必须考虑的硬性质量指标,若要把组件设计为通用组件提供给多种已知或未知的上层应用使用,则设计的难度更会大大增加,通用性、可用性和灵活性必须考虑在内。
1424 0