muduo的Channel类剖析


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 signalfd
class 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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值