muduo網路庫學習之EventLoop(五):TcpConnection生存期管理(連線關閉)
監聽套接字可讀事件是POLLIN; 已連線套接字正常可讀是POLLIN; 正常可寫是POLLOUT; 對等方close/shutdown關閉連線,已連線套接字可讀是POLLIN | POLLHUP;
時序圖分析:
![](https://i.iter01.com/images/17c44f098cef9cac2e9214d2e6faff6f719d836c4bdb714ee8c18b608d693c1f.png)
注意:將TcpConnectionPtr 在connections_ 中 erase 掉,時並不會馬上 析構TcpConnection 物件(引用計數不為0),
因為此時正處於Channel::handleEvent() 中,如果析構了TcpConnection,那麼它的成員channel_
也會被析構,即導致
core dump.
也就是說TcpConnection 物件生存期要長於handleEvent() 函式,直到執行完connectDestroyed() 後才會析構。
在EventLoop(三)的基礎上,在TcpConnection 建構函式中再新增:
C++ Code
1
2 3 4 5 6 |
// 連線關閉,回撥TcpConnection::handleClose
channel_->setCloseCallback( boost::bind(&TcpConnection::handleClose, this)); // 發生錯誤,回撥TcpConnection::handleError channel_->setErrorCallback( boost::bind(&TcpConnection::handleError, this)); |
在 TcpServer::newConnection() 中再新增:
C++ Code
1
2 3 4 5 6 |
void TcpServer::newConnection(int sockfd, const InetAddress &peerAddr)
{ ..... conn->setCloseCallback( boost::bind(&TcpServer::removeConnection, this, _1)); } |
在TcpConnection::handleRead() 中再新增:
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void TcpConnection::handleRead(Timestamp receiveTime) { ssize_t n = ::read(channel_->fd(), buf, sizeof buf); if (n > 0) { messageCallback_(shared_from_this(), buf, n); } else if (n == 0) { handleClose(); } else { errno = savedErrno; LOG_SYSERR << "TcpConnection::handleRead"; handleError(); } } |
假設現在已經建立了一個新連線,經過幾次收發資料後,對等方關閉close套接字,TcpConnection::channel_ 可讀事件發生,poll返
回,呼叫Channel::handleEvent()處理活動通道,呼叫TcpConnection::handleRead(),::read()
返回0,進而調
用TcpConnection::handleClose()
C++ Code
1
2 3 4 5 6 7 8 9 10 |
void TcpConnection::handleClose()
{ setState(kDisconnected); channel_->disableAll(); TcpConnectionPtr guardThis(shared_from_this()); connectionCallback_(guardThis);
// must be the last line closeCallback_(guardThis); // 呼叫TcpServer::removeConnection } |
這裡需要注意的是有關shared_from_this() 的使用:
C++ Code
1
2 |
class TcpConnection : boost::noncopyable,
public boost::enable_shared_from_this<TcpConnection> |
shared_from_this() 會用當前物件的裸指標構造一個臨時智慧指標物件,引用計數加1,但馬上會被析構,又減1,故無論呼叫多少
次,對引用計數都沒有影響。
TcpConnectionPtr guardThis(shared_from_this()); 為什麼不能直接寫成TcpConnectionPtr guardThis(this); ?
因為這樣寫的話,guardThis的引用計數就為1,而不是2,如下例所示:
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include<boost/enable_shared_from_this.hpp>
#include<boost/shared_ptr.hpp> #include<cassert> class Y: public boost::enable_shared_from_this<Y> { public: boost::shared_ptr<Y> f() { return shared_from_this(); } Y *f2() { return this; } }; int main(void) { boost::shared_ptr<Y> p(new Y); boost::shared_ptr<Y> q = p->f(); Y *r = p->f2(); assert(p == q); assert(p.get() == r); std::cout << p.use_count() << std::endl; //2 boost::shared_ptr<Y> s(r); std::cout << s.use_count() << std::endl; //1 assert(p == s); //斷言失敗 return 0; } |
直接用裸指標生成智慧指標物件s後,s的引用計數只是為1,而不會將p引用計數提升為3;如前所述,TcpConnection的生存期就會
成為問題,不能在恰當的時候被釋放。
進而呼叫TcpServer::removeConnection(),
C++ Code
1
2 3 4 5 6 7 8 |
void TcpServer::removeConnection(const TcpConnectionPtr &conn)
{ size_t n = connections_.erase(conn->name()); loop_->queueInLoop( boost::bind(&TcpConnection::connectDestroyed, conn)); } |
handleEvent() 處理完畢後,當前IO執行緒繼續執行doPendingFunctors() 函式,取出 TcpConnection::connectDestroyed() 執行:
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 |
void TcpConnection::connectDestroyed()
{ loop_->assertInLoopThread(); if (state_ == kConnected) { setState(kDisconnected); channel_->disableAll(); connectionCallback_(shared_from_this()); } channel_->remove(); //poll 不再關注此通道 } |
參考:
《UNP》
muduo manual.pdf
《linux 多執行緒伺服器程式設計:使用muduo c++網路庫》
相關文章
- 網路學習筆記(一):TCP連線的建立與關閉筆記TCP
- muduo網路庫Timestamp類
- muduo網路庫Exception異常類Exception
- muduo網路庫編譯安裝編譯
- 深度學習(五)之原型網路深度學習原型
- muduo網路庫AtomicIntegerT原子整數類
- 菜鳥學網路之 —— 長連線和短連線
- 網路 保證在關閉連線前, 把資料發出去
- 五分鐘瞭解網路連線
- 全連線神經網路學習筆記神經網路筆記
- 滲透測試學習之探測和攻擊無線網路五
- [從原始碼學設計]螞蟻金服SOFARegistry網路操作之連線管理原始碼
- 【機器學習】之第五章——神經網路機器學習神經網路
- Mudo C++網路庫第五章學習筆記C++筆記
- 使用screen讓關閉ssh連線時不關閉程式
- 資料庫學習線路圖資料庫
- Android連線網路資料庫的方式Android資料庫
- 網路安全需要學習哪些內容?網路安全線上學習
- 深度學習之Transformer網路深度學習ORM
- 測試主機網路連通性ping命令引數選項-linux網路管理學習Linux
- 資料庫學習(四)連線查詢資料庫
- 日常Bug排查-連線突然全部關閉
- 物聯網的學習路線
- 網路安全主要學習路線包含哪些?
- mysql階段04 連線工具, 連線方式, 啟動關閉mysqlMySql
- Vue3學習(五)之整合HTTP庫axiosVueHTTPiOS
- 深度學習之殘差網路深度學習
- 雲端計算學習路線教程大綱課件:網路管理基礎
- 深度學習2.0-12.神經網路與全連線層之資料集的載入深度學習神經網路
- SQL 資料庫學習路線推薦SQL資料庫
- IP協議:連線你我,掌握網際網路的關鍵協議
- VirtualBox網路連線方式
- RPC連線btcd網路RPC
- 網路、HTTP相關學習總結HTTP
- 無線網際網路協議802.11學習協議
- 使用iwctl連線無線網路
- 女生能學網路安全技術嗎?網路安全技術學習路線
- ClickHouse學習系列之五【系統庫system說明】
- Java 學習路線之四個階段Java