从epoll构建muduo-6 加入EventLoop和Epoll

mini-muduo版本传送门
version 0.00 从epoll构建muduo-1 mini-muduo介绍
version 0.01 从epoll构建muduo-2 最简单的epoll
version 0.02 从epoll构建muduo-3 加入第一个类,顺便介绍Reactor
version 0.03 从epoll构建muduo-4 加入Channel
version 0.04 从epoll构建muduo-5 加入Acceptor和TcpConnection
version 0.05 从epoll构建muduo-6 加入EventLoop和Epoll
version 0.06 从epoll构建muduo-7 加入IMuduoUser
version 0.07 从epoll构建muduo-8 加入发送缓冲区和接收缓冲区
version 0.08 从epoll构建muduo-9 加入onWriteComplate回调和Buffer
version 0.09 从epoll构建muduo-10 Timer定时器
version 0.11 从epoll构建muduo-11 单线程Reactor网络模型成型
version 0.12 从epoll构建muduo-12 多线程代码入场
version 0.13 从epoll构建muduo-13 Reactor + ThreadPool 成型

mini-muduo v0.05版本,完整可运行的示例可从github下载,使用命令git checkout v0.05可切换到此版本,在线浏览此版本到这里 本版将程序的主要类都加入进来了,这个版本可以作为一个里程碑版本,最重要的修改是加入了两个类EventLoop和Epoll。加入这两个类后,程序代码逻辑就相对清晰多了。为了有个更直观的了解,我们对照之前介绍的最简单epoll示例(从epoll构建muduo-2 最简单的epoll),看看原始示例里的关键代码现在都跑哪去了。

从epoll构建muduo-6 加入EventLoop和Epoll_第1张图片

1 先来看EventLoop,根据名字可以猜测这个类的作用是事件循环,其实这个类就是用来包装for循环的,也就是那个套在epoll_wait外面的for循环,这个for循环可以说是整个程序最核心的部分,for循环等待在epoll_wait上,然后遍历返回的每个事件,先通知到Channel,然后由Channel通知到最终的事件处理程序(位于Acceptor和TcpConnection中)。在上一个版本中。for循环位于TcpServer里,现在我们把它移动到EventLoop的loop方法里,用while代替for,作用跟之前的for循环一样:等待在epoll_wait上,当有事件发生时,回调Channel。当然,EventLoop::loop()不是直接调用epoll_wait,而是使用了其包装类Epoll。

2 Epoll类的作用是包装epoll文件描述符,它最重要的成员变量是一个epoll文件描述符,最重要的两个方法是poll和update。poll方法包装了epoll_wait,在epoll描述符上等待事件的发生,当有事件发生后将新建的Channel填充到vector中,update方法包装了epoll_ctl,用来在epoll文件描述符上添加/修改/删除事件。update接收一个Channel作为参数,通过这个Channel可以获得要注册的事件(Channel::getEvents()方法)。以后所有涉及epoll描述符的操作都通过Epoll的这两个方法来完成。EventLoop本来是应该包括一个epoll描述符的,loop方法通过一个循环来调用epoll_wait,而现在epoll描述符在Epoll中,所以EventLoop只需要包含一个Epoll成员变量即可。EventLoop在循环中只需要调用Epoll::poll()方法就可以获得Channel列表,不需要直接调用epoll_wait了。

3 Epoll和EventLoop应该是一一对应的关系,每个EventLoop有且只有一个Epoll。 在原始的muduo中,为了兼顾epoll/poll编程,作者为IO复用写了公共父类Poller,这里我进行了简化,直接实现了一个epoll的包装类Epoll而忽率了poll。

4 TcpServer也做了相应修改,在start方法里没有了epoll的创建过程,也没有了for循环。epoll的创建过程移动到Epoll的构造函数里。整个for循环都移动到EventLoop中,而真正启动循环的位置从TcpServer里移动到main函数里。TcpServer的另一处修改是将成员变量_epollfd换成EventLoop,因为EventLoop包含一个Epoll,而后者就是用来包装epoll文件描述符的,所以这个修改也很容易理解。

5 以前传递epollfd的地方,改为EventLoop* ,因为EventLoop和Epoll是一一对应的关系,而Epoll又是epollfd的包装,拿到EventLoop就等于拿到了epoll描述符。

6 Channel添加了方法getEvents()和getSockfd(),使Epoll可以通过Channel获得必须的events和fd。

7 新增了一处内存泄漏new Epoll 后续处理。

你可能感兴趣的:(linux,socket,epoll,网络编程,muduo)