muduo网络库学习(二)对套接字和监听事件的封装Channel
muduo對描述符fd,需要監聽的事件events,當fd被激活調用的可讀/可寫/關閉/錯誤回調函數進行了封裝,實現在Channel類中,Poller監聽的其實就是一個個Channel對象,Channel可以向Poller注冊自己關心的事件,當被激活后調用相應的回調函數。類似libevent的struct event。
Channel在整個事件驅動循環中的流程大致如下
其中
函數對象std::function
C++基于對象其實就是利用std::function/std::bind實現的,作用是綁定某個類的函數指針
使用方法如
std::function/std::bind為類的成員函數的調用提供更多靈活性,在C++11引入lambda后逐漸取代了std::bind,C++14后lambda支持模板參數后完全取代了std::bind
Channel定義如下,成員函數主要就是
.cpp中的幾個比較重要的函數介紹
/* * 由TcpConnection中connectEstablished函數調用* 作用是當建立起一個Tcp連接后,讓用于監測fd的Channel保存這個Tcp連接的弱引用* tie_是weak_ptr的原因* weak_ptr是弱引用,不增加引用基數,當需要調用內部指針時* 可通過lock函數提升成一個shared_ptr,如果內部的指針已經銷毀* 那么提升的shared_ptr是null* 可以通過是否是null判斷Tcp是否還處于連接,因為如果斷開,那么這個TcpConnection就被銷毀了*/ void Channel::tie(const std::shared_ptr<void>& obj) {tie_ = obj;tied_ = true; }因為Channel的回調函數其實調用的是TcpConnection中的函數,所以如果想要調用,就必須知道TcpConnection的指針,而如果TcpConnection被銷毀了,那么指針調用會出錯,所以采用智能指針,又因為Channel只需要知道TcpConnection是否還存在,所以不需要使用shared_ptr,這會增加引用計數,導致TcpConnection銷毀不了(如果close連接,TcpConnection本應該被銷毀,但是因為Channel中也留有對TcpConnection的引用,所以不會銷毀,糟糕的事情…),所以采用weak_ptr,不增加引用計數,適當時可以提升為shared_ptr
/** 根據fd激活事件的不同,調用不同的fd的回調函數*/ void Channel::handleEvent(Timestamp receiveTime) {/* * RAII,對象管理資源* weak_ptr使用lock提升成shared_ptr,此時引用計數加一* 函數返回,棧空間對象銷毀,提升的shared_ptr guard銷毀,引用計數減一*/std::shared_ptr<void> guard;if (tied_){guard = tie_.lock();if (guard){handleEventWithGuard(receiveTime);}}else{handleEventWithGuard(receiveTime);} }
經典的RAII應用場景,配合智能指針
如果想要判斷Channel所在的TcpConnection是否仍然存在(沒有被關閉),可以直接將weak_ptr提升為shared_ptr,如果提升成功(不為NULL),代表TcpConnection存在,調用回調函數即可。
提升成shared_ptr后TcpConnection引用計數變為2,handleEvent函數返回后局部變量guard銷毀,引用計數恢復到1。
同樣的應用還有鎖對象,創建時上鎖,析構時解鎖
handleEventWithGuard其實就是根據不同的激活原因滴啊用不同的回調函數,這些回調函數都在TcpConnection中,也是通過上面std::function/std::bind設置的,所以在調用前必須判斷Channel所在的TcpConnection是否還存在
/** 根據被激活事件的不同,調用不同的回調函數*/ void Channel::handleEventWithGuard(Timestamp receiveTime) {eventHandling_ = true;LOG_TRACE << reventsToString();if ((revents_ & POLLHUP) && !(revents_ & POLLIN)){if (logHup_){LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP";}if (closeCallback_) closeCallback_();}if (revents_ & POLLNVAL){LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL";}if (revents_ & (POLLERR | POLLNVAL)){if (errorCallback_) errorCallback_();}if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)){if (readCallback_) readCallback_(receiveTime);}if (revents_ & POLLOUT){if (writeCallback_) writeCallback_();}eventHandling_ = false; }總結
以上是生活随笔為你收集整理的muduo网络库学习(二)对套接字和监听事件的封装Channel的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: muduo网络库学习(一)对io复用的封
- 下一篇: muduo网络库学习(三)定时器Time