【muduo】net篇---Channel

  Channel类和文件描述符一一对应,它保存了所关心的文件描述符(fd_)、关注的事件(从TcpConnection那边注册的readCallback_、writeCallback_等)、poller返回的事件。Channel类对象被传到Poller类中进行poll(), 返回时,成员变量revents_会被改写,handleEvent正是根据这个revents_来执行读/写/出错操作(回调TcpConnection之前注册的函数)

#ifndef MUDUO_NET_CHANNEL_H
#define MUDUO_NET_CHANNEL_H

#include 
#include 
#include 
#include 

namespace muduo
{
namespace net
{

class EventLoop;

/******************************************************************** 
Modify : Eric Lee
Date : 2018-01-15 
Description : channel类(事件处理器)负责注册与响应I/O事件,但是它不
拥有文件描述符。每一个channel对象自始至终都只属于一个EventLoop。
*********************************************************************/
class Channel : noncopyable
{
 public:
  // 事件回调函数
  typedef std::function<void()> EventCallback;
  // 读事件回调函数
  typedef std::function<void(Timestamp)> ReadEventCallback;

  Channel(EventLoop* loop, int fd);
  ~Channel();

  // 处理事件
  void handleEvent(Timestamp receiveTime);
  // 设置读回调函数(参数是TcpConnection注册的)
  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); }

  // 把当前事件处理器绑定到某一个对象上
  void tie(const std::shared_ptr<void>&);

  // 返回文件描述符
  int fd() const { return fd_; }

  // 返回该事件处理所需要处理的事件
  int events() const { return events_; }
  // 设置实际活动的事件
  void set_revents(int revt) { revents_ = revt; }

  // 判断是否有事件
  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; }

  // 返回索引
  int index() { return index_; }
  // 设置索引
  void set_index(int idx) { index_ = idx; }

  // 用于调试,把事件转换为字符串
  string reventsToString() const;
  string eventsToString() const;

  // 不记录hup事件
  void doNotLogHup() { logHup_ = false; }

  // 所属的事件循环(一个EventLoop可以有多个channel,但是一个channel只属于一个EventLoop)
  EventLoop* ownerLoop() { return loop_; }

  // 从事件循环对象中把自己删除
  void remove();

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

  // 更新
  void update();

  // 处理事件
  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_;   // 表示在poll事件数组中的序号
  bool       logHup_;

  std::weak_ptr<void> tie_;
  bool tied_;
  bool eventHandling_; // 是否正在处理事件
  bool addedToLoop_; // 是否已经被添加到事件循环中
  // 事件回调
  ReadEventCallback readCallback_;
  EventCallback writeCallback_;
  EventCallback closeCallback_;
  EventCallback errorCallback_;
};

}  // namespace net
}  // namespace muduo

#endif  // MUDUO_NET_CHANNEL_H
#include 
#include 
#include 
#include 
#include 

using namespace muduo;
using namespace muduo::net;

// POLLPRI:表示对应的文件描述符有紧急的数据可读
// POLLIN:表示对应的文件描述符可以读
// POLLOUT:表示对应的文件描述符可以写
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),
    addedToLoop_(false)
{
}

// 销毁事件处理器
Channel::~Channel()
{
  assert(!eventHandling_);
  assert(!addedToLoop_);
  if (loop_->isInLoopThread())
  {
    assert(!loop_->hasChannel(this));
  }
}

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

// 更新通道,调用EventLoop::updateChannel(),接着又会调用poller::updatechannel()
void Channel::update()
{
  addedToLoop_ = true;
  loop_->updateChannel(this);
}

// 移除通道
void Channel::remove()
{
  assert(isNoneEvent());
  addedToLoop_ = false;
  loop_->removeChannel(this);
}

void Channel::handleEvent(Timestamp receiveTime)
{
  std::shared_ptr<void> guard;
  if (tied_)
  {
    guard = tie_.lock();
    if (guard) // 确保对象还活着
    {
      handleEventWithGuard(receiveTime);
    }
  }
  else
  {
    handleEventWithGuard(receiveTime);
  }
}

/******************************************************************** 
Modify : Eric Lee
Date : 2018-01-15 
Description : 根据revents_的值,分别调用不同的回调函数。
*********************************************************************/
void Channel::handleEventWithGuard(Timestamp receiveTime)
{
  eventHandling_ = true;
  LOG_TRACE << reventsToString();
  // 对方套接字关闭
  if ((revents_ & POLLHUP) && !(revents_ & 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))
  {
    if (readCallback_) readCallback_(receiveTime);
  }
  if (revents_ & POLLOUT)
  {
    if (writeCallback_) writeCallback_();
  }
  eventHandling_ = 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();
}

你可能感兴趣的:(muduo网络库)