muduo源码剖析 - Channel

说明

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.其他函数大部分是比较简单辅助函数,例如日志信息,不做多余赘述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YanWenCheng_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值