本章讲解我觉得本项目最关键的组件:Epoll和Reactor,这两个组件共同完成了一项任务:监听HTTP请求然后把他们分别转发到SubReactor中处理。

  1. Epoll代码讲解:
    include //这个提供固定宽度的整数类型,也就是占多少字节多少位规定好的类型,int或者long在不同平台上不一样,所以用这个适合协议,和系统API对接。
    include <unordered_map>
    include <unordered_set>
    include
    include <sys/epoll.h>

namespace atlas{
class Epoll{
public:
struct Event{
int fd;
uint32_t events;
void* userData;
};

explicit Epoll(int maxEvents=1024);
~Epoll();

Epoll(const Epoll&)=delete;
Epoll& operator=(const Epoll&)=delete;

void addFd(int fd,uint32_t events,void* userData=nullptr);
void modFd(int fd,uint32_t events,void* userData=nullptr);
void delFd(int fd);
int wait(std::vector<Event>& events,int timeoutMs=-1);

int getFd()const{return epfd_;}
bool hasFd(int fd)const;

private:
uint32_t toEpollEvents(uint32_t events)const;
uint32_t fromEpollEvents(uint32_t events)const;

int epfd_;
int maxEvents_;
std::unordered_set<int> fds_;
std::unordered_map<int,void*> fdToUserData_;

};
}
endif

首先Event是一个请求,表示哪个fd现在有可读或者是可写的请求,不是内容本身。void*是通用指针,不关心挂哪种对象只负责把某个指针和fd绑定在一起然后事件来了原样返回。

重点来了,toEpollEvents是这个思路:epoll只会告诉用户几号fd有数据了,用户需要根据fd找到在程序中对应的Connection对象然后调用其handleRead函数。所以就需要一个表,记录fd->传进来的指针。一句话:fdToUserData_ 就是「fd 几号 → 是哪个 Connection」的登记表,方便事件回来时找到人

2.Reactor基类:Epoll事件循环,其实就是对epoll的高级封装

3.MainReactor类:对Reactor的继承,仅仅负责accept新连接,分发给SubReactor,其实就是对Reactor加上了连接请求和分发给SubReactor