muduo_net代码剖析之事件处理器Channel

引言

  1. 必须将产生事件的文件描述符封装在Channel。这里的文件描述符可以是file descriptor,可以是socket,还可以是timefd,signalfd。
  2. 文件描述符是最终需要加入到linux的epoll或者select等IO复用设施上的

Channel简介

    Channel相当于libevent中的事件event

    Channel是Reactor结构中的“事件”,它自始至终都只属于一个EventLoop,每个Channel对象自始至终只负责一个fd的IO事件分发。

==> 可以将Channel安插到EventLoop上,用EventLoop监视该Channel,当EventLoop监视到Channel关注的事件发生时,就会回调Channel的事件回调函数。

Channel的使用步骤

在这里插入图片描述

Channel的使用步骤
构造函数构造Channel对象:使用fd创建Channel对象,并给Channel关联EventLoop
set___CallBack给Channel对象注册Read/Write回调函数
enable*、disable*调用enable*、disable*给Channel对象关注和取消读写事件
loop()调用EventLoop的poll/epoll循环监控Channel对象可读/可写事件是否被触发,一旦触发,立即执行注册的回调函数

源码剖析

根据[Channel的使用步骤]对源码进行剖析

1. 构造函数
Channel::Channel(EventLoop* loop, int fd__)
  : loop_(loop), //该Channel所属的loop
    fd_(fd__), //关联的文件描述符fd
    events_(0),  //关注的事件
    revents_(0), //epoll/poll返回的被激活的事件
    index_(-1),
    logHup_(true),
    tied_(false),
    eventHandling_(false), //是否处于事件处理中
    addedToLoop_(false)
{
}
2. set___CallBack:给Channel对象注册Read/Write回调函数

(1) 回调函数的类型分为两大类

//事件回调处理
typedef std::function<void()> EventCallback;
//读事件的回调处理,传一个时间戳
typedef std::function<void(Timestamp)> ReadEventCallback;

(2) 成员函数

private:
  ReadEventCallback readCallback_;
  EventCallback writeCallback_;
  EventCallback closeCallback_;
  EventCallback errorCallback_;

(3) 设置回调函数set___Callback
设置回调函数,实际上是将用户自定义的回调函数,给成员函数赋值

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); }
3. enable\*、disable\*: 调用enable*、disable*给Channel对象关注取消读写事件
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(); }

void Channel::update() //更新事件类型
{
  addedToLoop_ = true;
  loop_->updateChannel(this); 
}

执行时序图
(1) 当Channel调用enable*、disable*,修改了关注的事件events_后,将调用update()函数
(2) update函数,调用了loop_->updateChannel(this),将该Channel从Poller::channels_删除或添加到Poller::channels_中
在这里插入图片描述

4. 调用loop->loop()监控事件的发生,当关注的事件发生后,会回调通过set___Callback注册的回调函数

解释:由前面的博文muduo_net代码剖析之EventLoop

void EventLoop::loop()
{
... ...
  while (!quit_)
  {
... ...
    for (Channel* channel : activeChannels_)
    {
      currentActiveChannel_ = channel;
      
      //激活的Channel,调用handleEvent
      //handleEvent又去回调通过set___Callback设置的回调函数
      currentActiveChannel_->handleEvent(pollReturnTime_);
    }
... ...
  }
... ...
}
void Channel::handleEvent(Timestamp receiveTime)
{
  std::shared_ptr<void> guard;
  if (tied_)
  {
    guard = tie_.lock();
    if (guard)
    {
      handleEventWithGuard(receiveTime);
    }
  }
  else
  {
    handleEventWithGuard(receiveTime);
  }
}
//事件发生后,根据事件类型来调用之前使用set___Callback注册的回调函数
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_();
  }
  
  //POLLIN:listsock有新的连接到来、sockfd可读
  //POLLRDHUP:对端关闭连接事件,如shutdown等
  if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))
  {
    if (readCallback_) readCallback_(receiveTime);
  }
  
  //outputBuffer_中有数据,导致sockfd可写
  //   将outputBuffer_中的数据写入到sockfd(即内核中的缓冲区)中
  if (revents_ & POLLOUT)
  {
    if (writeCallback_) writeCallback_();
  }
  eventHandling_ = false;//处理完了=false
}
... ...

示例代码

timerfd_create 生成一个定时器对象,返回文件描述符
timerfd_settime 能够启动和停止定时器
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值