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