net2. Reactor关键结构——Channel通道类

时序图:
在这里插入图片描述
Channel类

  1. muduo中通过Channel对fd进行封装,fd可以是file descriptor,可以是socket,还可以是timefd,signalfd。其实更合适的说法是对fd事件相关方法的封装,例如负责注册fd的可读或可写事件到EvenLoop,又如fd产生事件后要如何响应。
  2. 一个fd对应一个channel, 它们是聚合关系,Channel在析构函数中并不会close掉这个fd(如socket是通过Socket类的对象离开临界区时close的,即RAII技法)。
  3. 它有一个handleEvent方法,当该fd有事件产生时EvenLoop会调用handleEvent方法进行处理,在handleEvent内部根据可读或可写事件调用不同的回调函数(回调函数可事先注册)。
  4. Channel类一般都不是单独使用的,通常都是用作其他类的成员,比如EvenLoop、TcpConnection、Acceptor、Connector这几个类。例如EvenLoop通过一个vector<Channel*> 对注册到其内的众多fd的管理,毕竟有了Channel就有了fd及其对应的事件处理方法,所以你会看到上图中EvenLoop与Channel是一对多的关系。
  5. Channel对象读写、更新都在一个I/O线程,读写不需要加锁。

数据成员:

static const int kNoneEvent:常量,表示没有事件
static const int kReadEvent:常量,表示读事件
static const int kWriteEvent:常量,表示写事件
EventLoop* loop_:Channel所属的EventLoop
const int fd_:Channel所负责的文件描述符,但不负责关闭该文件描述符
int events_:关注的事件
int revents_:poll/epoll返回的事件
int index_:如果使用的是PollPoller,表示该通道关注的事件在poll的事件数组中的序号;如果使用的是EPollPoll,表示通道的状态
bool logHup_:for POLLHUP
boost::weak_ptr tie_
bool tied_
bool eventHandling_:当前是否处于事件处理的状态
ReadEventCallback readCallback_:读回调函数
EventCallback writeCallback_:写回调函数
EventCallback closeCallback_:关闭回调函数
EventCallback errorCallback_:错误回调函数

typedef

typedef boost::function<void()> EventCallback:EventCallback是事件的回调处理
typedef boost::function<void(Timestamp)> ReadEventCallback:ReadEventCallback是读事件的回调处理

成员函数:

Channel(EventLoop* loop, int fd):构造函数,Channel记录Channel所属的EventLoop对象
~Channel():析构函数
void handleEvent(Timestamp receiveTime):当事件到来时,会调用handleEvent()进行处理
void setReadCallback(const ReadEventCallback& cb):读回调函数的注册,负责对所发生的I/O事件进行处理
void setWriteCallback(const EventCallback& cb):写回调函数的注册,负责对所发生的I/O事件进行处理
void setCloseCallback(const EventCallback& cb):关闭回调函数的注册,负责对所发生的I/O事件进行处理
void setErrorCallback(const EventCallback& cb):错误回调函数的注册,负责对所发生的I/O事件进行处理
void tie(const boost::shared_ptr&);
int fd() const :返回Channel所对应的文件描述符
int events() const :返回Channel关注的事件
void set_revents(int revt) :设置poll/epoll返回的事件
int revents() const :返回poll/epoll返回的事件的数目
bool isNoneEvent() const :判断是否没有事件发生,即判断events_是否等于kNoneEvent
void enableReading() :通道关注可读事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
void disableReading() :通道不关注可读事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
void enableWriting() :通道关注可写事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
void disableWriting() :通道不关注可写事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
void disableAll() :通道不关注所有事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
bool isWriting() const :判断当前通道是否关注写事件
int index():返回index
void set_index(int idx) :令poll的事件数组中的序号index_=idx
string reventsToString() const:把事件转换成字符串,以便调试
void doNotLogHup() :返回logHup_
EventLoop* ownerLoop():返回Channel所属的EventLoop,即loop_
void remove():负责移除I/O的可读或可写等事件
void update():负责更注册或者更新I/O的可读或可写等事件
void handleEventWithGuard(Timestamp receiveTime):handleEvent()会调用handleEventWithGuard()对事件进行处理

Channel.h

#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:

  //EventCallback是事件的回调处理
  typedef boost::function<void()> EventCallback;
  //ReadEventCallback是读事件的回调处理
  typedef boost::function<void(Timestamp)> ReadEventCallback;
  
  //一个Channel对象只能属于一个EventLoop对象
  //一个EventLoop对象可以拥有多个Channel对象
  //Channel构造函数记录Channel所属的EventLoop对象
  Channel(EventLoop* loop, int fd);
  ~Channel();
  
  //当事件到来时,会调用handleEvent()进行处理
  void handleEvent(Timestamp receiveTime);
  //回调函数的注册,负责对所发生的I/O事件进行处理
  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; }

  /// 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>&);
  //返回Channel所对应的文件描述符
  int fd() const { return fd_; }
  //返回Channel注册的事件的数目events_
  int events() const { return events_; }
  //设置poll/epoll返回的事件的数目
  void set_revents(int revt) { revents_ = revt; } // used by pollers
  //返回poll/epoll返回的事件的数目
  //int revents() const { return revents_; }
  //判断是否没有事件发生,即判断events_是否等于kNoneEvent
  bool isNoneEvent() const { return events_ == kNoneEvent; }
  
  //通道关注可读事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
  void enableReading() { events_ |= kReadEvent; update(); }
  //通道不关注可读事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
  //void disableReading() { events_ &= ~kReadEvent; update(); }
  //通道关注可写事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
  void enableWriting() { events_ |= kWriteEvent; update(); }
  //通道不关注可写事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
  void disableWriting() { events_ &= ~kWriteEvent; update(); }
  //通道不关注所有事件,调用update()把这个通道注册到EventLoop所持有的poller_对象中
  void disableAll() { events_ = kNoneEvent; update(); }
  //判断当前通道是否关注写事件
  bool isWriting() const { return events_ & kWriteEvent; }

  // for Poller
  //返回index_
  int index() { return index_; }
  //令poll的事件数组中的序号index_=idx
  void set_index(int idx) { index_ = idx; }

  // for debug
  //把事件转换成字符串,以便调试
  string reventsToString() const;
  
  //返回logHup_
  void doNotLogHup() { logHup_ = false; }
  
  //返回Channel所属的EventLoop,即loop_
  EventLoop* ownerLoop() { return loop_; }
  //负责移除I/O的可读或可写等事件
  void remove();

 private:
  //负责更注册或者更新I/O的可读或可写等事件
  void update();
  //handleEvent()会调用handleEventWithGuard()对事件进行处理
  void handleEventWithGuard(Timestamp receiveTime);
  
  //常量,表示没有事件
  static const int kNoneEvent;
  //常量,表示读事件
  static const int kReadEvent;
  //常量,表示写事件
  static const int kWriteEvent;

  //Channel所属的EventLoop
  EventLoop* loop_;			
  //文件描述符,但不负责关闭该文件描述符
  const int  fd_;			
  //关注的事件
  int        events_;		
  //poll/epoll返回的事件
  int        revents_;		
  //如果使用的是PollPoller,表示该通道关注的事件在poll的事件数组中的序号
  //如果使用的是EPollPoll,表示通道的状态
  int        index_;		
  //for POLLHUP
  bool       logHup_;		

  boost::weak_ptr<void> tie_;
  bool tied_;
  //当前是否处于事件处理的状态
  bool eventHandling_;	
  //四个回调函数
  ReadEventCallback readCallback_;
  EventCallback writeCallback_;
  EventCallback closeCallback_;
  EventCallback errorCallback_;
};

}
}
#endif  // MUDUO_NET_CHANNEL_H

Channel.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;
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)
{
}

Channel::~Channel()
{
  assert(!eventHandling_);
}

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

void Channel::update()
{
  loop_->updateChannel(this);
}

// 调用这个函数之前确保调用disableAll
void Channel::remove()
{
  assert(isNoneEvent());
  loop_->removeChannel(this);
}

void Channel::handleEvent(Timestamp receiveTime)
{
  boost::shared_ptr<void> guard;
  if (tied_)
  {
    guard = tie_.lock();
    if (guard)
    {
      handleEventWithGuard(receiveTime);
    }
  }
  else
  {
    handleEventWithGuard(receiveTime);
  }
}

void Channel::handleEventWithGuard(Timestamp receiveTime)
{
  eventHandling_ = true;
  if ((revents_ & POLLHUP) && !(revents_ & POLLIN))
  {
    if (logHup_)
    {
      LOG_WARN << "Channel::handle_event() POLLHUP";
    }
    if (closeCallback_) closeCallback_();
  }

  if (revents_ & POLLNVAL)
  {
    LOG_WARN << "Channel::handle_event() POLLNVAL";
  }

  if (revents_ & (POLLERR | POLLNVAL))
  {
    if (errorCallback_) errorCallback_();
  }
  if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))
  {
    if (readCallback_) readCallback_(receiveTime);
  }
  if (revents_ & POLLOUT)
  {
    if (writeCallback_) writeCallback_();
  }
  eventHandling_ = false;
}

string Channel::reventsToString() const
{
  std::ostringstream oss;
  oss << fd_ << ": ";
  if (revents_ & POLLIN)
    oss << "IN ";
  if (revents_ & POLLPRI)
    oss << "PRI ";
  if (revents_ & POLLOUT)
    oss << "OUT ";
  if (revents_ & POLLHUP)
    oss << "HUP ";
  if (revents_ & POLLRDHUP)
    oss << "RDHUP ";
  if (revents_ & POLLERR)
    oss << "ERR ";
  if (revents_ & POLLNVAL)
    oss << "NVAL ";

  return oss.str().c_str();
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值