此学习笔记参考施磊老师的muduo教学课程。
目的是搞懂 muduo 网络库的核心框架。EventLoop、channel 和 Poller 之间的关系
整体框架如下:
muduo是基于 Reactor 模式的网络库,他有三个核心组件支撑一个 reactor 实现持续的监听一组fd,并根据每个 fd 上发生的事件调用相应的处理函数。这三个组件分别是 Channel 类、Poll类以及EventLoop类。
EventLoop 是 Reactor 的核心,主要负责事件分发。在事件分发器中有两个重要部分,分别为 Poller 和 Channel。
1 Poller 抽象基类
说到事件循环,最常见的有 select、poll、epoll 等,在 muduo 中,选择使用抽象基类 Poller 来定义,在派生基类中实现 poll 和 epoll 。
// EventLoop.h 中的定义
std::unique_ptr<Poller> poller_;
// DefaultPoller.cc
#include <stdlib.h>
#include "Poller.h"
#include "EPollPoller.h"
Poller *Poller::newDefaultPoller(EventLoop *loop)
{
// getenv 环境变量
if (::getenv("MUDUO_USE_POLL"))
{
return nullptr; // 生成poll的实例,这里没有实现
}
else
{
return new EPollPoller(loop); // 生成epoll的实例
}
}
在 EPollPoller 中的 epoll 实现,需要考虑 epoll 所感兴趣的事件 event, 在 event 中绑定了一个 sockfd 以及它所感兴趣的事件,这些都封装在 Channel 中。
// channel.h 中的成员变量
const int fd_; // fd,Poller监听的对象
int events_; // 注册fd感兴趣的事件
int revents_; // Poller返回的具体发生的事件
2 Channel
它是 EventLoop 的另一个重要部分,Channel理解为通道,它封装了sockfd 和其感兴趣的 event 如 EPOLLIN、EPOLLOUT 事件,还绑定了 poller 返回的具体事件
// EventLoop.h 中的定义
using ChannelList = std::vector<Channel*>;
所有的成员函数都在这里:
channel中的成员函数
这里只说明一些:
在 Channel 中使用智能指针,是防止我们手动调用了 removeChannel后,还在使用已经被删除的 Channel。它完成跨线程状态的监听。weak_ptr 和 shared_ptr 配合使用,可以解决 shared_ptr 的值循环引用的问题,在多线程中使用 weak_ptr来监听它所观察的资源的状态,使用时尝试提升为 shared_ptr ,提升成功,访问,提升失败,就不访问,说明它所观察的资源已经被释放。
std::weak_ptr<void> tie_; // 防止手动 remove Channel后仍在执行回调操作。
bool tied_;
智能指针的学习参考:
C++基础——智能指针 shared_ptr 和 weak_ptr 的使用
C++智能指针 shared_ptr,unique_ptr和weak_ptr
当 poller 中有监听事件,channel 就会调用相应的回调。
// 设置fd相应的事件状态 相当于 epoll_ctl add delete
/*
const int Channel::kNoneEvent = 0;
const int Channel::kReadEvent = EPOLLIN | EPOLLPRI;
const int Channel::kWriteEvent = EPOLLOUT;
*/
void enableReading() {
events_ |= kReadEvent; update(); } // 让 fd 对读事件感兴趣
void disableReading() {
events_ &= ~kReadEvent; update(); } // ~:使得read的那一位是0,,再&=上其他位,把相应的位置成0,去掉,
void enableWriting() {
events_ |= kWriteEvent; update(); }
void disableWriting() {
events_ &= ~kWriteEvent; update(); }
void disableAll() {
events_ = kNoneEvent; update(); }
3 模块的包含
前面说过,EventLoop 是 Reactor 的核心,主要负责事件分发。在事件分发器中有两个重要部分,分别为 Poller 和 Channel。
根据高性能服务器模型:one loop per thread,可以得出一个线程中有一个EventLoop ,一个EventLoop 中有一个poller,一个 poller 上可以监听很多 channel。
所一个channel有一个 EventLoop,一个 EventLoop 有多个channel。