
1.Channel1Channel的定位Channel 是一个“事件监听器”和“回调调度员”。它内部持有a.一个文件描述符fd_——比如listenfd或connfd。b.它关心的事件events_——想监听读写c.实际发生的事件revents_——epoll返回的实际事件。d.事件发生后的处理函数readCallback_/writeCallback_。在整个架构中evenloop负责驱动循环epollPoller负责调用epoll_wait监控事件Channel是具体的操作者把fd、事件、回调打包在一起当这个fd出现时由Channel调用回调函数。Channel.h#ifndef MUDUO_CHANNEL_H #define MUDUO_CHANNEL_H #include functional //前向声明作用告诉编译器“有EventLoop这个类它定义在别处”。 //这里只需要EventLoop*指针不需要完整定义避免头文件循环包含。 class EventLoop; //Channel封装了一个fd及其关心的事件和回调 class Channel { public: //回调函数类型无参数无返回值的函数,用来装readCallback_和writeCallback_。 //为什么无参因为回调执行时Channel已经把需要的信息都存到了自己的成员变量里回调 //可以直接访问不需要参数 using EventCallback std::functionvoid(); //构造时传入Channel所属的EventLoop的指针和fd初始化成员变量。 Channel(EventLoop* loop, int fd); ~Channel(); //设置回调函数(外部传入) //由TcpConnection在构造时调用把handleRead和handleWrite绑定进来。 //关键解耦点Channel本身不知道业务逻辑是什么它只负责在事件发生时调用这些回调。 void setReadCallback(const EventCallback cb) { readCallback_ cb; } void setWriteCallback(const EventCallback cb) { writeCallback_ cb; } //获取基本信息 int fd() const { return fd_; } //返回管理的文件描述符 int events() const { return events_; } //返回当前关心的事件掩码比如kReadEvent int revents() const { return revents_; } //返回实际发生的事件掩码 //Poller 用这个设置实际发生了什么事件 //由 EpollPoller::poll() 在 epoll_wait 返回后调用把内核返回的事件写入 revents_。 //之后 EventLoop 会调用 channel-handleEvent()handleEvent 通过 revents_ 判断发生了什么 //事件。 void set_revents(int revt) { revents_ revt; } //|按位或开启某个事件。events_ | 1 表示把读事件位设为 1。 // ~按位与 取反关闭某个事件。events_ ~1 表示把读事件位清 0。 //调用 update()每次修改 events_ 后都要通知 EventLoop 去更新 epoll 的注册。 //启用/禁用读监听 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(); } //判断当前状态 //用来判断当前是否在监听读/写事件在 handleWrite 里经常用到比如数据发完后如果还在监听 //写事件就取消它。 bool isWriting() const { return events_ kWriteEvent; } bool isReading() const { return events_ kReadEvent; } //更新到 epoll (通过 EventLoop 转发给 Poller) void update(); //处理事件(epoll_wait 返回后调用) void handleEvent(); private: //事件类型常量(对应epoll的EPOLLIN/EPOLLOUT) //值的选择刻意与epoll的宏对齐。 //为什么要自定义而不是直接用 EPOLLIN //为了屏蔽底层细节。Channel 层只认 kReadEvent不管底层是 epoll、poll 还是 select。 //将来如果要换 I/O 多路复用机制只需要在 Poller 层做翻译Channel 的代码完全不用改。这就是 //muduo 的“可扩展性”设计。 static const int kNoneEvent 0; static const int kReadEvent 1; // EPOLLIN static const int kWriteEvent 4; // EPOLLOUT static const int kErrorEvent 8; // EPOLLERR | EPOLLHUP EventLoop* loop_;//所属的EventLoop所有 I/O 操作都在这个线程里。 int fd_; // 这个Channel管理的文件描述符 int events_; // 关心什么事件读写 int revents_; //实际发生了什么事件epoll_wait返回的 EventCallback readCallback_; EventCallback writeCallback_; }; #endifChannel.cpp#include Channel.h #include EventLoop.h Channel::Channel(EventLoop* loop, int fd) : loop_(loop) , fd_(fd) , events_(0) , revents_(0) { } Channel::~Channel() {} //修改了关心的事件之后更新到epoll void Channel::update() { //EventLoop会转发给Poller(下一步实现) loop_-updateChannel(this); } //epoll_wait返回后根据发生的事件调用对应回调 void Channel::handleEvent() { // 检查错误事件由 Poller 层转换后的 kErrorEvent // 错误事件优先级最高先处理 if (revents_ kErrorEvent) { if (errorCallback_) { errorCallback_(); } return; // 出错后不再处理其他事件 } //如果发生的是读事件执行读回调 if (revents_ kReadEvent) { if (readCallback_) { readCallback_(); } } //如果发生的是写事件执行写回调 if (revents_ kWriteEvent) { if (writeCallback_) { writeCallback_(); } } }//修改了关心的事件之后更新到epoll void Channel::update() { //EventLoop会转发给Poller(下一步实现) loop_-updateChannel(this); }作用 通知EventLoop 更新 epoll 注册- 调用loop_-updateChannel(this)- EventLoop 会转发给Poller- Poller 调用epoll_ctl 更新注册调用链 Channel::update()→ EventLoop::updateChannel(channel)→ Poller::updateChannel(channel)→ epoll_ctl(epollfd_, operation, fd, ev)//epoll_wait返回后根据发生的事件调用对应回调 void Channel::handleEvent() { // 检查错误事件由 Poller 层转换后的 kErrorEvent // 错误事件优先级最高先处理 if (revents_ kErrorEvent) { if (errorCallback_) { errorCallback_(); } return; // 出错后不再处理其他事件 }作用 处理错误事件- revents_ kErrorEvent 检查是否有错误事件- errorCallback_() 调用错误回调- return 出错后不再处理其他事件为什么错误事件优先级最高- 错误发生时连接可能已经不可用- 继续处理读/写事件可能导致崩溃- 应该立即关闭连接//如果发生的是读事件执行读回调 if (revents_ kReadEvent) { if (readCallback_) { readCallback_(); } }作用 处理读事件- revents_ kReadEvent 检查是否有读事件- readCallback_() 调用读回调使用场景 - TcpConnection 读取数据- Acceptor 接受新连接- EventLoop 读取 eventfd跨线程唤醒- TimerQueue 读取 timerfd定时器超时//如果发生的是写事件执行写回调 if (revents_ kWriteEvent) { if (writeCallback_) { writeCallback_(); } } }作用 处理写事件- revents_ kWriteEvent 检查是否有写事件- writeCallback_() 调用写回调使用场景 - TcpConnection 继续发送缓冲的数据