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();
}
来源:oschina
链接:https://my.oschina.net/u/4342549/blog/4554832