muduo_net代码剖析之Channel

版权声明:guojawee https://blog.csdn.net/weixin_36750623/article/details/84400407

Channel简介

  1. Channel是Reactor结构中的“事件”,它自始至终都属于一个EventLoop,相当于libevent中的event_base,可以将event_base安插到EventLoop上,用EventLoop监视该Channel
  2. Channel负责一个文件描述符的IO事件,它包含文件描述符fd_,但实际上它不拥有fd_,不用负责将其关闭。
  3. 在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对象可读/可写事件是否被触发,一旦触发,立即执行注册的回调函数
  1. Channel类有EventLoop的指针 loop_,通过这个指针可以向EventLoop中添加当前Channel事件。事件类型用events_表示,不同事件类型对应不同回调函数
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;
  1. 调用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_;
  
... ...
};

Channel.cc

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_);
    }
    ... ...
  }
... ...
}

示例代码2

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_36750623/article/details/84400407
今日推荐