muduo源码解析25-网络库3:channel类最终版
channel类:
说明:
为了更好地管理channel,在channel中添加一些额外的成员变量/函数。使其和muduo源码一致
channel.h:
#ifndef CHANNEL_H #define CHANNEL_H #include"base/noncopyable.h" #include"base/timestamp.h" #include<memory> #include<functional> namespace mymuduo { namespace net { class eventloop; class channel:noncopyable { public: typedef std::function<void()> EventCallback; typedef std::function<void(timestamp)> ReadEventCallback; channel(eventloop* loop,int fd); ~channel(); //处理网络事件 void handleEvent(timestamp recieve); //设置四个回调函数,read,write,close,error Callback函数,在处理event时被调用 void setReadCallback(ReadEventCallback cb) { m_readCallback = std::move(cb); } void setWriteCallback(EventCallback cb) { m_writeCallback = std::move(cb); } void setCloseCallback(EventCallback cb) { m_closeCallback=std::move(cb);} void setErrorCallback(EventCallback cb) { m_errorCallback = std::move(cb); } void tie(const std::shared_ptr<void>&); int fd()const {return m_fd;} //channel所负责IO事件的那个fd //返回当前channel所注册的网络事件 int events() const{return m_events;} void set_revents(int revt){m_revents=revt;} //设置网络事件 //判断当前channel是否注册了事件 bool isNoneEvent() const{return m_events==kNoneEvent;} //在m_event上注册读/写事件 void enableReading(){m_events|=kReadEvent;update();} void enableWriting(){m_events|=kWriteEvent;update();} //在m_event上取消读/写事件 void disableReading(){m_events&=~kReadEvent;update();} void disableWriting(){m_events&=~kWriteEvent;update();} //取消m_event所有事件 void disableAll(){m_events=kNoneEvent;update();} //判断m_event是否注册了读/写事件 bool isWriting() const{return m_events & kWriteEvent;} bool isReading() const{return m_events & kWriteEvent;} //for poller,当前channel在poller::m_pollfds中的位置 int index(){return m_index;} void set_index(int idx){m_index=idx;} //for debug string reventsToString()const; string eventsToString() const; //是否打印日志 void doNotLogHup(){m_logHup=false;} //返回当前channel所在的那个eventloop eventloop* ownerLoop(){return m_loop;} //让eventloop移除自身这个channel void remove(); private: static string eventsToString(int fd,int ev); //让本channel 所属于的那个eventloop回调channel::update()完成channel的更新 //实际上最终在poller中被更新 void update(); //在handleEvent()内部使用的具体的实现 void handleEventWithGuard(timestamp receiveTime); //这三个静态常量分别表示:无网络事件,读网络事件,写网络事件 static const int kNoneEvent; static const int kReadEvent; static const int kWriteEvent; eventloop* m_loop; //channel所属的那个eventloop const int m_fd; //每个channel负责处理一个sockfd上的网络事件 int m_events; //channel注册(要监听)的网络事件 int m_revents; //poll()返回的网络事件,具体发生的事件 int m_index; //这个channel在poller中m_pollfds中的序号,默认-1表示不在其中 bool m_logHup; //是否打印日志 std::weak_ptr<void> m_tie; //??? bool m_tied; // bool m_eventHandling; //是否正在处理网络事件 bool m_addedToLoop; //是否被添加到eventloop中执行 //当发生了读/写/错误网络事件时,下面几个函数会被调用 ReadEventCallback m_readCallback; EventCallback m_writeCallback; EventCallback m_closeCallback; EventCallback m_errorCallback; }; }//namespace net }//namespace mymuduo #endif // CHANNEL_H
channel.cpp
#include "channel.h" #include"base/logging.h" #include"net/channel.h" #include"net/eventloop.h" #include<sstream> #include<poll.h> namespace mymuduo { namespace net { const int channel::kNoneEvent=0; const int channel::kReadEvent=POLLIN|POLLPRI; const int channel::kWriteEvent=POLLOUT; //构造函数,根据sockfd创建一个对应的channel,仅初始化成员 channel::channel(eventloop* loop,int fd) :m_loop(loop),m_fd(fd),m_events(0),m_revents(0),m_index(-1), m_logHup(true),m_tied(false),m_eventHandling(false),m_addedToLoop(false) { } //保证这个channel析构时,eventloop不再持有这个channel channel::~channel() { assert(!m_eventHandling); assert(!m_addedToLoop); if(m_loop->isInLoopThread()) assert(!m_loop->hasChannel(this)); } //此时eventloop::loop()中poll函数返回,说明有网络事件发生了, //内部利用handleEventWithGuard()实现对各个网络事件的处理 void channel::handleEvent(timestamp receiveTime) { std::shared_ptr<void> guard; if (m_tied) { guard = m_tie.lock(); if (guard) { handleEventWithGuard(receiveTime); } } else { handleEventWithGuard(receiveTime); } } void channel::tie(const std::shared_ptr<void> &obj) { m_tie=obj; m_tied=true; } //for debug string channel::reventsToString()const { return eventsToString(m_fd,m_revents); } string channel::eventsToString() const { return eventsToString(m_fd,m_events); } //把网络事件转化成字符串格式 string channel::eventsToString(int fd, int ev) { std::ostringstream oss; oss << fd << ": "; if (ev & POLLIN) oss << "IN "; if (ev & POLLPRI) oss << "PRI "; if (ev & POLLOUT) oss << "OUT "; if (ev & POLLHUP) oss << "HUP "; if (ev & POLLRDHUP) oss << "RDHUP "; if (ev & POLLERR) oss << "ERR "; if (ev & POLLNVAL) oss << "NVAL "; return oss.str(); } //让eventloop删除这个channel void channel::remove() { assert(isNoneEvent()); m_addedToLoop=false; m_loop->removeChannel(this); } //让本channel 所属于的那个eventloop回调channel::update()完成channel的更新 void channel::update() { m_addedToLoop=true; m_loop->updateChannel(this); } //channel::handleEvent()的内部实现,根据不同的网络事件调用不同的回调处理 void channel::handleEventWithGuard(timestamp receiveTime) { m_eventHandling = true; LOG_TRACE << reventsToString(); //处理关闭事件 if ((m_revents & POLLHUP) && !(m_revents & POLLIN)) { if (m_logHup) { LOG_WARN << "fd = " << m_fd << " Channel::handle_event() POLLHUP"; } if (m_closeCallback) m_closeCallback(); } if (m_revents & POLLNVAL) { LOG_WARN << "fd = " << m_fd << " Channel::handle_event() POLLNVAL"; } //处理错误事件 if (m_revents & (POLLERR | POLLNVAL)) { if (m_errorCallback) m_errorCallback(); } //处理读网络事件 if (m_revents & (POLLIN | POLLPRI | POLLRDHUP)) { if (m_readCallback) m_readCallback(receiveTime); } //处理写网络事件 if (m_revents & POLLOUT) { if (m_writeCallback) m_writeCallback(); } m_eventHandling = false; } }//namespace net }//namespace mymuduo
注意:析构函数中调用eventloop::hasChannel()和remove函数中eventloop::removeChannel()目前还没有在eventloop类中实现,这里先说一下,他们的作用就是判断当前channel是否在eventloop中,以及让在eventloop中移除这个channel