muduo的Channel类剖析

来源:互联网 发布:中老年品位 知乎 编辑:程序博客网 时间:2024/05/22 06:17


Channel类,即通道类。

>它是muduo库负责注册读写事件的类,并保存了fd读写事件发生时调用的回调函数,如果poll/epoll有读写事件发生则将这些事件添加到对应的通道中。

>一个通道对应唯一EventLoop,一个EventLoop可以有多个通道。

>Channel类不负责fd的生存期,fd的生存期是有socket决定的,断开连接关闭描述符。

>当有fd返回读写事件时,调用提前注册的回调函数处理读写事件


下面是源码解析:

#ifndef MUDUO_NET_CHANNEL_H#define MUDUO_NET_CHANNEL_H#include <boost/function.hpp>#include <boost/noncopyable.hpp>#include <boost/shared_ptr.hpp>#include <boost/weak_ptr.hpp>#include <muduo/base/Timestamp.h>namespace muduo{namespace net{class EventLoop;////// A selectable I/O channel.////// This class doesn't own the file descriptor./// The file descriptor could be a socket,/// an eventfd, a timerfd, or a signalfdclass Channel : boost::noncopyable{ public:  typedef boost::function<void()> EventCallback;  //事件回调处理  typedef boost::function<void(Timestamp)> ReadEventCallback;  //读事件的回调处理,传一个时间戳  Channel(EventLoop* loop, int fd);  //一个Channel一个EventLoop  ~Channel();  void handleEvent(Timestamp receiveTime);  //处理事件  void setReadCallback(const ReadEventCallback& cb)   //设置各种回调函数  { readCallback_ = cb; }  void setWriteCallback(const EventCallback& cb)  { writeCallback_ = cb; }  void setCloseCallback(const EventCallback& cb)  { closeCallback_ = cb; }  void setErrorCallback(const EventCallback& cb)  { errorCallback_ = cb; }#ifdef __GXX_EXPERIMENTAL_CXX0X__  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); }#endif  /// Tie this channel to the owner object managed by shared_ptr,  /// prevent the owner object being destroyed in handleEvent.  void tie(const boost::shared_ptr<void>&); //与TcpConnection有关,防止事件被销毁。  int fd() const { return fd_; }  //描述符  int events() const { return events_; }   //注册的事件  void set_revents(int revt) { revents_ = revt; } // used by pollers  // int revents() const { return revents_; }  bool isNoneEvent() const { return events_ == kNoneEvent; }  //判断是否无关注事件类型,events为0  void enableReading() { events_ |= kReadEvent; update(); }   //或上事件,就是关注可读事件,注册到EventLoop,通过它注册到Poller中  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_; }   //pollfd数组中的下标  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();  //移除,确保调用前调用disableall。 private:  static string eventsToString(int fd, int ev);  void update();  void handleEventWithGuard(Timestamp receiveTime);  static const int kNoneEvent;   //三个常量,没有事件,static常量类外部有定义,在.cc文件中  static const int kReadEvent;   //可读事件  static const int kWriteEvent;  //可写事件  EventLoop* loop_;   //记录所属EventLoop  const int  fd_;         //文件描述符,但不负责关闭改描述符  int        events_;   //关注的时间类型  int        revents_; // it's the received event types of epoll or poll  int        index_; // used by Poller.,表示在Poller事件数组中的序号  bool       logHup_;  //for POLLHUP  boost::weak_ptr<void> tie_;  //负责生存期控制  bool tied_;  bool eventHandling_;         //是否处于处理事件中  bool addedToLoop_;  ReadEventCallback readCallback_;   //几种事件处理回调  EventCallback writeCallback_;  EventCallback closeCallback_;  EventCallback errorCallback_;};}}#endif  // MUDUO_NET_CHANNEL_H

.cc文件:

#include <muduo/base/Logging.h>#include <muduo/net/Channel.h>#include <muduo/net/EventLoop.h>#include <sstream>#include <poll.h>using namespace muduo;using namespace muduo::net;const int Channel::kNoneEvent = 0;   //集中事件类型定义const int Channel::kReadEvent = POLLIN | POLLPRI; //PRI比如TCP的带外数据const int Channel::kWriteEvent = POLLOUT;Channel::Channel(EventLoop* loop, int fd__)  : 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));  }}void Channel::tie(const boost::shared_ptr<void>& obj){  tie_ = obj;  tied_ = true;}void Channel::update()   //更新事件类型{  addedToLoop_ = true;  loop_->updateChannel(this);  //调用loop的,loop再调用poll的注册pollfd}void Channel::remove()  //移除{  assert(isNoneEvent());  addedToLoop_ = false;  loop_->removeChannel(this);}void Channel::handleEvent(Timestamp receiveTime) //事件到来调用handleEvent处理{  boost::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}string Channel::reventsToString() const{  return eventsToString(fd_, revents_);}string Channel::eventsToString() const{  return eventsToString(fd_, events_);}string Channel::eventsToString(int fd, int ev)   //调试输出发生了什么事件{  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().c_str();}



0 0
原创粉丝点击