说明
Channel类, 是selectable IO channel,负责注册与响应IO事件,它并不管理file descriptor. 它是Acceptor,Connector,EventLoop,TimeQueue,TcpConnection的成员,生命周期由后者控制。需要往EventLoop注册事件的类都必须使用channel。
可以看做是只为一个对象服务的观察者。 例如:
1 .TCPConnection 的观察者,TCPConnection注册读写事件的回调(TCPConnection为监听者)2. Acceptor 的观察者,Acceptor 注册读事件的回调(Acceptor为监听者)
成员
重点关注以下几个成员
event, revent :注册的事件和Poller响应的事件
loop:当前channel所属的loop,每个channel事件只能被一个loop管理,poller中管理着当前loop的所有channel。这里就是为了和channel的管理者通信(注册事件,取消事件)。
ReadEventCallback readCallback_:读回调
EventCallback writeCallback_:写回调
EventCallback closeCallback_: 关闭回调
EventCallback errorCallback_: 错误回调
static const int kNoneEvent;
static const int kReadEvent;
static const int kWriteEvent;
EventLoop* loop_;
const int fd_; //文件描述符,构造函数中指定, 但是不管理他,只是关联关系
int events_; //poll关注事件的种类,是POLLIN|POLLPRI还是POLLOUT还是0,revnets_是pollfd结构的revents,这里需要知道关于poll()的知识
int revents_; // it's the received event types of epoll or poll
int index_; // used by Poller. //对于PollPoller要用,小于0(初始化)表示是一个新的Channel,还没加入poll关注,否则是更新一个存在的Channel,对于EPollPoller,有三种:-1,1,2,分别表示新的,已添加,已删除
bool logHup_; //如果有POLLHUP事件,是否要打印日志,POLLHUP是当socket的另一端关闭时,或读到文件结尾,会收到pollhup事件
std::weak_ptr<void> tie_; //tie和tied需要在TCPConnection理解
bool tied_;
bool eventHandling_; //是否处于处理事件的过程中,即是否是handleEventWithGuard()函数调用过程中
bool addedToLoop_; //判断当前channel是否加入事件关注
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;
方法
1. 对event的操作:对poll关注事件的设置,注册事件和取消事件。(此操作是上层TcpConnection等具体对象管理者调用。)
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; }
重点在update函数 ,将自己的this给他的事件管理者loop,loop里面的poller获取到当前对象并进行更新。
//调用loop_的updateChannel(this),改变通道信息
void Channel::update()
{
addedToLoop_ = true;
loop_->updateChannel(this);
}
2. 对revent操作:这里通过事件管理者poller设置。poller通知当前发生事件。
void set_revents(int revt) { revents_ = revt; } // used by pollers
// for Poller
int index() { return index_; }
void set_index(int idx) { index_ = idx; }
3. handleEvent() :特别重要,Eventloop的loop函数就是每次获得活跃channel,然后通过每个channel的handleEvent来处理具体事件的。
//这里由channel所在的loop调用
void Channel::handleEvent(Timestamp receiveTime)
{
std::shared_ptr<void> guard;
if (tied_)
{
guard = tie_.lock();
if (guard)
{
handleEventWithGuard(receiveTime);
}
}
else
{
handleEventWithGuard(receiveTime);
}
}
//对应的poll事件选择相应的回调函数进行执行
void Channel::handleEventWithGuard(Timestamp receiveTime)
{
eventHandling_ = true;
LOG_TRACE << reventsToString();
if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) //POLLHUP发生说明对面关闭了
{
if (logHup_)
{
LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP";
}
if (closeCallback_) closeCallback_();
}
if (revents_ & POLLNVAL) //POLLNVAL说明文件描述符没有打开
{
LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL";
}
if (revents_ & (POLLERR | POLLNVAL)) //POLLERR | POLLNVAL 错误、文件描述符没有打开
{
if (errorCallback_) errorCallback_();
}
if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) //POLLIN | POLLPRI | POLLRDHUP,可读,带外,写关闭
{
if (readCallback_) readCallback_(receiveTime);
}
if (revents_ & POLLOUT) //可写事件
{
if (writeCallback_) writeCallback_();
}
eventHandling_ = false;
}
4.其他函数大部分是比较简单辅助函数,例如日志信息,不做多余赘述