muduo/net/Channel.h
muduo/net/Channel.cc
Channel可理解为一个文件描述符fd和如何处理它的事件的回调函数的封装。
Channel负责注册和响应IO事件。
muduo用户一般不直接使用Channel,而使用更上一层的封装,如TCPConnetion。
这里是一个给出的测试示例
#include <muduo/net/Channel.h> #include <muduo/net/EventLoop.h> #include <boost/bind.hpp> #include <stdio.h> #include <sys/timerfd.h> using namespace muduo; using namespace muduo::net; EventLoop* g_loop; int timerfd; void timeout() { printf("Timeout!\n"); //uint64_t howmany; ::read(timerfd, &howmany, sizeof howmany); g_loop->quit(); //退出 } int main(void) { EventLoop loop; g_loop = &loop; //使用timerfd实现一个单次触发的定时器 timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); Channel channel(&loop, timerfd); //该channel的fd即定时器的fd channel.setReadCallback(timeout);//设置读事件的回调函数 channel.enableReading(); struct itimerspec howlong; bzero(&howlong, sizeof howlong); howlong.it_value.tv_sec = 5; //设置定时时间5s,定时时间到则触发事件 ::timerfd_settime(timerfd, 0, &howlong, NULL); loop.loop(); //开启loop循环,监听事件 ::close(timerfd); }
成员函数与变量小窥,主要是文件描述符和事件的回调函数。
一个Channel负责一个文件描述符fd的IO事件分发。
这里说到Channel不管理fd的生命期,即析构时不会关闭fd。
/// A selectable I/O channel. /// /// This class doesn't own the file descriptor. /// The file descriptor could be a socket, /// an eventfd, a timerfd, or a signalfd class Channel : noncopyable { public: typedef std::function<void()> EventCallback; typedef std::function<void(Timestamp)> ReadEventCallback; Channel(EventLoop* loop, int fd); ~Channel(); void handleEvent(Timestamp receiveTime); void setReadCallback(ReadEventCallback cb) //设置读事件回调函数 { readCallback_ = std::move(cb); } void setWriteCallback(EventCallback cb) //写事件回调函数 { writeCallback_ = std::move(cb); } void setCloseCallback(EventCallback cb) //关闭事件回调函数 { closeCallback_ = std::move(cb); } void setErrorCallback(EventCallback cb) //异常事件回调函数 { errorCallback_ = std::move(cb); } /// Tie this channel to the owner object managed by shared_ptr, /// prevent the owner object being destroyed in handleEvent. void tie(const std::shared_ptr<void>&); int fd() const { return fd_; } int events() const { return events_; } void set_revents(int revt) { revents_ = revt; } // used by pollers // int revents() const { return revents_; } bool isNoneEvent() const { return events_ == kNoneEvent; } void enableReading() { events_ |= kReadEvent; update(); } void disableReading() { events_ &= ~kReadEvent; update(); } void enableWriting() { events_ |= kWriteEvent; update(); } void disableWriting() { events_ &= ~kWriteEvent; update(); } void disableAll() { events_ = kNoneEvent; update(); } bool isWriting() const { return events_ & kWriteEvent; } bool isReading() const { return events_ & kReadEvent; } // for Poller int index() { return index_; } void set_index(int idx) { index_ = idx; } // for debug string reventsToString() const; string eventsToString() const; void doNotLogHup() { logHup_ = false; } EventLoop* ownerLoop() { return loop_; } void remove(); private: static string eventsToString(int fd, int ev); void update(); void handleEventWithGuard(Timestamp receiveTime); static const int kNoneEvent; static const int kReadEvent; static const int kWriteEvent; EventLoop* loop_; //每个Channel只属于一个Eventloop const int fd_; //所管理的文件描述符 int events_; //监听的事件 int revents_; // poller返回的事件 int index_; // used by Poller.Poller管理多个Channel,用index标识该channel bool logHup_; std::weak_ptr<void> tie_; bool tied_; bool eventHandling_; bool addedToLoop_; ReadEventCallback readCallback_; EventCallback writeCallback_; EventCallback closeCallback_; EventCallback errorCallback_; }; //Channel.cc const int Channel::kNoneEvent = 0; const int Channel::kReadEvent = POLLIN | POLLPRI; const int Channel::kWriteEvent = POLLOUT;
Channel::handleEvent()是Channel的核心,功能是根据poller返回的事件revents的值分别调用不同的用户回调函数。handleEvents()由EventLoop::loop()调用。
void Channel::handleEvent(Timestamp receiveTime) { std::shared_ptr<void> guard; if (tied_) { guard = tie_.lock(); if (guard) { handleEventWithGuard(receiveTime); } } else { //上面暂时不用管,直接看作调用了handleEventWithGuard() handleEventWithGuard(receiveTime); } } void Channel::handleEventWithGuard(Timestamp receiveTime) { eventHandling_ = true; LOG_TRACE << reventsToString(); //revents即poll/epoll返回的活跃事件 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; }