码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-06-23 08:26:05      阅读:348      评论:0      收藏:0      [点我收藏+]

标签:class   blog   code   http   tar   com   

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

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

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

中的Client对象:

 

  1. #include "core/connection.h"  
  2. #include <vector>  
  3.   
  4. using namespace std;  
  5.   
  6. class Client: public Connection<Client> {  
  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一般情况下是不需要的

 

  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.   
  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。

在以后的文章中会探索。

boost::asio 连接管理11 如何关闭连接,布布扣,bubuko.com

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

标签:class   blog   code   http   tar   com   

原文地址:http://www.cnblogs.com/lidabo/p/3799293.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!