<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    boost::asio 連接管理11 如何關閉連接

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    在實際產品運行中,對連接管理有了更新的認識,這里分享一下。

    shared_ptr管理連接對象的生命周期

    shared_ptr的引用計數器決定了連接對象的生命周期。這里我說的連接對象就是在我的前文:http://blog.csdn.net/csfreebird/article/details/8522620

    中的Client對象:

     

    [cpp] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片  
    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一般情況下是不需要的

     

    [cpp] view plaincopyprint?在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不允許這樣做。

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

     

    異步讀/寫阻塞導致連接對象無法銷毀

    如果就堅持不用CloseSocket行么,我碰到另一種情況,async_write/async_read會阻塞,結果shared_ptr的引用計數不會為0,所以Client對象無法被銷毀。那么怎么安全的調用CloseSocket的呢?用strand,下面是代碼:

     

    [cpp] view plaincopyprint?  
    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。

    在以后的文章中會探索。

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全