相关文件
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源码分析
Channel类
成员函数与变量小窥,主要是文件描述符和事件的回调函数。
一个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;
}