免费搭建网站,光速网站建设,做技术一般逛那些网站,如何做网站的导航栏Muduo库源码剖析(一)——Channel
说明
本源码剖析是在muduo基础上#xff0c;保留关键部分进行改写分析。
要点总结
事件分发器 event dispatcher中最重要的两个类型 channel 和 Poller
Channel可理解为通道#xff0c;poller往通道传输数据(事件发生情况)。
EventLoop…Muduo库源码剖析(一)——Channel
说明
本源码剖析是在muduo基础上保留关键部分进行改写分析。
要点总结
事件分发器 event dispatcher中最重要的两个类型 channel 和 Poller
Channel可理解为通道poller往通道传输数据(事件发生情况)。
EventLoop包含多个channel 和一个 Poller
Channel相当于是对socket的事件处理封装包含了socket的详细信息scoket以及感兴趣的事件都在channel里
channel是muduo库负责注册读写事件的类并保存了fd读写事件发生时调用的回调函数如果poll/epoll有读写事件发生则将这些事件添加到对应的通道中。 一个channel对应唯一EventLoop一个EventLoop可以有多个channel。 Channel类不负责fd的生存期fd的生存期是由socket决定的断开连接关闭描述符。 当有fd返回读写事件时调用提前注册的回调函数处理读写事件 头文件中只给类的前置声明而在源文件中再给出头文件包含因为源文件会被编程动态库.so, 减少对外暴露 weak_ptr 用于观察绑定对象的状态并且可以尝试提升为shared_ptr
Channel这个模块对应Reactor模型上的 Demultiplex 多路复用器 重点代码详解
// Channel.h
#pragma once#include noncopyable.h
#include Timestamp.h#include functional
#include memory// 头文件中只给类的前置声明而在源文件中再给出头文件包含
// 因为源文件会被编程动态库.so, 减少对外暴露
class EventLoop;class Channel : noncopyable
{
public:using EventCallback std::functionvoid();using ReadEventCallback std::functionvoid(Timestamp);Channel(EventLoop *loop, int fd);~Channel();// fd得到poller通知后调用其处理事件void handleEvent(Timestamp recevieTime);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的所有者被手动remove掉时Channel 仍在执行回调void tie(const std::shared_ptrvoid); // 检测资源存活状态int fd() const { return fd_; }int events() const { return events_; }void set_revents(int revt) { revents_ revt; }// 设置fd相应的事件状态// enableReading 让fd对读事件感兴趣// update()底层也是调用 epoll_ctlvoid enableReading() { events_ | kReadEvent; update(); }void disableReading() { events_ ~kReadEvent; update(); }void enableWriting() { events_ | kWriteEvent; update(); }void disableWriting() { events_ ~kWriteEvent; update(); }void disableAll() { events_ kNoneEvent; }int index() { return index_; }void set_index(int idx) { index_ idx; }// oneloop per thread// 当前Channel所属的eventloopEventLoop* ownerLoop() {return loop_;}void remove();private:void update();void handleEventWithGuard(Timestamp recvTime);static const int kNoneEvent; // 感兴趣的事件类型该变量表示不感兴趣任何事件static const int kReadEvent; static const int kWriteEvent; EventLoop *loop_; // 事件循环const int fd_; //fd poller监听的对象int events_; // 注册感兴趣的事件int revents_; // poller返回的具体发生的事件类型可读可写int index_;std::weak_ptrvoid tie_; // 用于观察shared_ptr的状态bool tied_;// 因为Channel里能得知fd最终发生的具体事件revents_// 故它负责调用对应的回调ReadEventCallback readCallback_;EventCallback writeCallback_;EventCallback closeCallback_;EventCallback errorCallback_;};// Channel.cpp
#include Channel.h
//#include EventLoop.h
#include Logger.h#include sys/epoll.hconst int Channel::kNoneEvent 0;
const int Channel::kReadEvent EPOLLIN | EPOLLPRI;
const int Channel::kWriteEvent EPOLLOUT;Channel::Channel(EventLoop *loop, int fd): loop_(loop), fd_(fd), events_(0), revents_(0), index_(-1), tied_(false)
{
}Channel::~Channel()
{
}// ??channel的tie方法什么时候调用过
void Channel::tie(const std::shared_ptrvoid obj)
{tie_ obj;tied_ true;
}// 当改变Channel所表示fd的events事件后update负责在poller里更改fd相应事件--epoll_ctl
// EventLoop has ChannelList Poller
void Channel::update()
{// 通过Channel所属的EventLoop调用Poller的相应方法注册fd的events事件// [TODO]// loop_-updateChannel(this);
}// 在Channel所属的EventLoop中把当前Channel删除
void Channel::remove()
{// [TODO]// loop_-removeChannel(this);
}// fd得到poller通知后处理事件
void Channel::handleEvent(Timestamp receiveTime)
{if(tied_) // 资源存活{std::shared_ptrvoid guard tie_.lock();if(guard){handleEventWithGuard(receiveTime);}}else {handleEventWithGuard(receiveTime);}
}// 根据Poller通知的Channel发生的具体事件调用相应的回调
void Channel::handleEventWithGuard(Timestamp receiveTime)
{LOG_INFO(channel handleEvent revents:%d\n, revents_);// EPOLLHUP 表示读写都关闭if((revents_ EPOLLHUP) !(revents_ EPOLLIN)){if(closeCallback_){closeCallback_();}}if(revents_ EPOLLERR){if(errorCallback_){errorCallback_();}}if(revents_ (EPOLLIN | EPOLLPRI)){if(readCallback_){readCallback_(receiveTime);}}if(revents_ EPOLLOUT){if(writeCallback_){writeCallback_();}}}
参考资料 陈硕. 《LInux多线程服务端编程》 施磊. 《手写CMuduo网络库》