2.muduo之Channel

£可爱£侵袭症+ 提交于 2020-09-29 16:56:12

Channel类主要作用:1.将文件描述符(可能是socket类型,eventfd类型,timefd类型,signalfd类型)封装,通过该类设置各种事件的回调函数(例如读回调,写回调,关闭回调等)。2.可以设置自己的监听事件类型,然后根据该类型更新poller对象(epoll或者poll)对该类的操作(例如添加,修改,删除操作)。3.根据自己监听到的事件类型触发回调函数。

1.Channel.h文件

///
///一个能被选择的 I/O channel
//这个类不拥有自己的文件描述符
/// 这个文件描述符可能是socket,eventfd, timerfd,或者 signalfd.

class Channel : noncopyable
{
 public:
  typedef std::function<void()> EventCallback;	//事件回调
  typedef std::function<void(Timestamp)> ReadEventCallback;	//读事件回调

  Channel(EventLoop* loop, int fd);	//一个channel属于一个loop,一个loop可以对应多个channel
  ~Channel();

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

  /// 将此channel与shared_ptr管理的所有者对象绑定,
  ///阻止shared_ptr管理的所有者对象在handleEvent被销毁
  void tie(const std::shared_ptr<void>&);

  int fd() const { return fd_; }
  int events() const { return events_; }	//返回注册的事件
  void set_revents(int revt) { revents_ = revt; } // 设置监听到的事件类型
  // int revents() const { return revents_; }
  bool isNoneEvent() const { return events_ == kNoneEvent; }

  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_; }	//poller事件数组中的下标
  void set_index(int idx) { index_ = idx; }	

  // for debug
  string reventsToString() const;
  string eventsToString() const;

  void doNotLogHup() { logHup_ = false; }

  EventLoop* ownerLoop() { return loop_; }	//返回所属的loop
  void remove();	//将channel从loop中移除

 private:
  static string eventsToString(int fd, int ev);

  void update();	//根据index_的状态,控制监听数组
  void handleEventWithGuard(Timestamp receiveTime);	//对监听到事件的一个处理

  static const int kNoneEvent;
  static const int kReadEvent;
  static const int kWriteEvent;

  EventLoop* loop_;
  const int  fd_;
  int        events_;	//监听的事件类型
  int        revents_; 	//监听到的事件类型 
  int        index_; 	// 表示poller事件数组中的序号
  bool       logHup_;	

  std::weak_ptr<void> tie_;
  bool tied_;	
  bool eventHandling_;	//是否处于处理事件中
  bool addedToLoop_;	//是否添加到loop上
  ReadEventCallback readCallback_;	//读回调
  EventCallback writeCallback_;	//写回调
  EventCallback closeCallback_;	//关闭回调
  EventCallback errorCallback_;	//错误回调
};

2.Channel.cc文件

const int Channel::kNoneEvent = 0;
const int Channel::kReadEvent = POLLIN | POLLPRI;
const int Channel::kWriteEvent = POLLOUT;

Channel::Channel(EventLoop* loop, int fd__)
  : loop_(loop),	//从属的loop
    fd_(fd__),		
    events_(0),		
    revents_(0),
    index_(-1),
    logHup_(true),
    tied_(false),
    eventHandling_(false),
    addedToLoop_(false)
{
}

Channel::~Channel()
{
  assert(!eventHandling_);
  assert(!addedToLoop_);
  if (loop_->isInLoopThread())
  {
    assert(!loop_->hasChannel(this));	//该对象此时不属于loop_并且poller中也没有该记录才能销毁成功
}

void Channel::tie(const std::shared_ptr<void>& obj)
{
  tie_ = obj;
  tied_ = true;
}

void Channel::update()	//根据index_的状态,控制该channel的监听状态
{
  addedToLoop_ = true;
  loop_->updateChannel(this);	//该函数最底层实际是由Poller->updateChannel(this)实现的
}

void Channel::remove()
{
  assert(isNoneEvent());
  addedToLoop_ = false;
  loop_->removeChannel(this);	//将该对象从Poller监听的数组对象中移除出去
}

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)) //POLLHUP:对方描述符挂起 POLLIN:普通或优先级带数据可读
  {
    if (logHup_)
    {
      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流套接字的远程端断开连接,或者关闭了写段。要获得此概念要求宏_GNU_SOURCE必须定义
  {
    if (readCallback_) readCallback_(receiveTime);	//调用回调读函数
  }
  if (revents_ & POLLOUT)	//如果监听到的是写事件,则调用回调写函数
  {
    if (writeCallback_) writeCallback_();
  }
  eventHandling_ = false;	//事件处理完成,将事件处理标志职位false
}

string Channel::reventsToString() const	//将revents转为string,方便输出调试
{
  return eventsToString(fd_, revents_);
}

string Channel::eventsToString() const	//将events转为string,方便输出调试
{
  return eventsToString(fd_, events_);
}

string Channel::eventsToString(int fd, int ev)	//实际上events和revents转为string类型的实现
{
  std::ostringstream oss;
  oss << fd << ": ";
  if (ev & POLLIN)
    oss << "IN ";
  if (ev & POLLPRI)
    oss << "PRI ";
  if (ev & POLLOUT)
    oss << "OUT ";
  if (ev & POLLHUP)
    oss << "HUP ";
  if (ev & POLLRDHUP)
    oss << "RDHUP ";
  if (ev & POLLERR)
    oss << "ERR ";
  if (ev & POLLNVAL)
    oss << "NVAL ";

  return oss.str();
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!