本文包含以下内容:
- epoll是如何工作的
本文不包含以下内容:
- epoll 的用法
- epoll 的缺陷
epoll实现原理由视频讲解:
C/C++ Linux服务器开发高级架构学习视频点击:C/C++Linux服务器开发/Linux后台架构师-学习视频教程
epoll原理剖析以及reactor模型应用
基于linux epoll网络编程细节处理
我实在非常喜欢像epoll这样使用方便、原理不深却有大用处的东西,即使它可能已经比较老了
select 和 poll 的缺点
epoll 对于动辄需要处理上万连接的网络服务应用的意义可以说是革命性的。对于普通的本地应用,select 和 poll可能就很好用了,但对于像C10K这类高并发的网络场景,select 和 poll就捉襟见肘了。
看看他们的API
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
它们有一个共同点,用户需要将监控的文件描述符集合打包当做参数传入,每次调用时,这个集合都会从用户空间拷贝到内核空间,这么做的原因是内核对这个集合是无记忆的。对于绝大部分应用,这是一种十足的浪费,因为应用需要监控的描述符在大部分时间内基本都是不变的, 也许会有变化, 但都不大.
epoll 对此的改进
epoll对此的改进也正是它的实现方式, 它需要完成以下两件事
- 描述符添加 --- 内核可以记下用户关心哪些文件的哪些事件.
- 事件发生 --- 内核可以记下哪些文件的哪些事件真正发生了, 当用户前来获取时, 能把结果提供给用户.
描述符添加
既然要有记忆, 那么理所当然的内核需要需要一个数据结构来记, 这个数据结构简单点就像下面这个图中的epoll_instance, 它有一个链表头,链表上的元素epoll_item就是用户添加上去的, 每一项都记录了描述符fd和感兴趣的事件组合event
事件发生
事件有多种类型, 其中POLLIN表示的可读事件是用户使用的最多的。比如:
- 当一个 TCP 的socket收到报文,它会变得可读;
- 当一个pipe受到对端发送的数据,它会变得可读;
- 当一个timerfd对应的定时器超时,它会变得可读;
那么现在需要将这些可读事件和前面的epoll_instance关联起来。linux中,每一个文件描述符在内核都有一个struct file结构对应, 这个struct fil