版权声明:guojawee https://blog.csdn.net/weixin_36750623/article/details/84400407
Channel简介
- Channel是Reactor结构中的“事件”,它自始至终都属于一个EventLoop,相当于libevent中的event_base,可以将event_base安插到EventLoop上,用EventLoop监视该Channel
- Channel负责一个文件描述符的IO事件,它包含文件描述符fd_,但实际上它不拥有fd_,不用负责将其关闭。
- 在Channel类中保存这IO事件的类型以及对应的回调函数,当IO事件发生时,最终会调用到Channel类中的回调函数。Channel类一般不单独使用,它常常包含在其他类中(Acceptor、Connector、EventLoop、TimerQueue、TcpConnection)使用。
Channel的使用步骤
Channel的使用步骤 |
---|
构造Channel对象:使用fd创建Channel对象,并给Channel关联EventLoop |
给Channel对象注册Read/Write回调函数 |
调用enable*、disable*给Channel对象关注和取消读写事件 |
调用EventLoop的poll/epoll循环监控Channel对象可读/可写事件是否被触发,一旦触发,立即执行注册的回调函数 |
- Channel类有EventLoop的指针 loop_,通过这个指针可以向EventLoop中添加当前Channel事件。事件类型用events_表示,不同事件类型对应不同回调函数
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;
- 调用enable*、disable*关注和取消读写事件,都调用了update()函数,update()函数更新关心事件的时序图:
Channel源码分析
Channel.h
class EventLoop;
class Channel : noncopyable
{
public:
typedef std::function<void()> EventCallback;//事件回调处理
typedef std::function<void(Timestamp)> ReadEventCallback;//读事件的回调处理,传一个时间戳
Channel(EventLoop* loop, int fd);//构造函数
~Channel();
//在EventLoop::loop()中调用了handleEvent()函数,用于处理被激活的事件
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); }
... ...
//添加/删除修改的事件,调用了update()函数
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 const int kNoneEvent;
static const int kReadEvent;
static const int kWriteEvent;
EventLoop* loop_; //所属EventLoop
const int fd_; //文件描述符,但是不负责关闭该fd
int events_; //关注的事件
int revents_; //epoll/poll返回的事件
int index_; // used by Poller.表示在poll事件数组中的序号
bool logHup_;// for POLLHUP
std::weak_ptr<void> tie_;
bool tied_;
bool eventHandling_; //是否处于处理事件中
bool addedToLoop_;
... ...
};
const int Channel::kNoneEvent = 0;
const int Channel::kReadEvent = POLLIN | POLLPRI;
const int Channel::kWriteEvent = POLLOUT;
... ...
void Channel::update() //更新事件类型
{
addedToLoop_ = true;
loop_->updateChannel(this); //调用loop的,loop再调用poll的注册pollfd
}
... ...
void Channel::handleEvent(Timestamp receiveTime)
{
std::shared_ptr<void> guard;
if (tied_)
{
guard = tie_.lock();
if (guard)
{
handleEventWithGuard(receiveTime);
}
}
else
{
handleEventWithGuard(receiveTime);
}
}
//事件发生后,根据事件类型来调用回调函数
void Channel::handleEventWithGuard(Timestamp receiveTime)
{
eventHandling_ = true;
LOG_TRACE << reventsToString();
if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) //判断返回事件类型
{
if (logHup_)//如果有POLLHUP事件,输出警告信息
{
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))//POLLRDHUP是对端关闭连接事件,如shutdown等
{
if (readCallback_) readCallback_(receiveTime);
}
if (revents_ & POLLOUT)
{
if (writeCallback_) writeCallback_();
}
eventHandling_ = false;//处理完了=false
}
... ...
handleEvent()函数的使用示例
示例代码1
在EventLoop类的成员函数EventLoop::loop()中,调用了handleEvent(),用于处理激活的事件
//事件循环,该函数不能跨线程调用,只能在创建该对象的线程中调用
void EventLoop::loop()
{
... ...
while (!quit_)
{
... ...
//遍历每一个激活的通道currentActiveChannel_,并handleEvent
for (Channel* channel : activeChannels_)
{
currentActiveChannel_ = channel;
currentActiveChannel_->handleEvent(pollReturnTime_);
}
... ...
}
... ...
}