1.epoll
epoll是linux特有的I/O复用函数。它在实现和使用上与select、poll有很大差异。
- 首先,epoll使用一组函数来完成任务,而不是单个函数。
- 其次,epoll把用户关心的文件描述符上的事件放在内核里的一个事件表中,从而无须像select和poll那样每次调用都要重复传入文件描述符集或事件集。
- 但epoll需要使用一个额外的文件描述符,来唯一标示内核中的这个事件表。
- 这个文件描述符使用
epoll_create
函数来创建:
size参数现在不起作用,只是给内核一个提示,告诉它事件表需要多大。#include <sys/epoll.h> int epoll_create(int size);
epoll_ctl
用来操作epoll的内核事件表。epoll系列系统调用的主要接口是
epoll_wait
函数。epoll对文件描述符的操作有两种模式:LT和ET
- LT(Level Trigger,电平触发)模式是默认的工作模式,在这种模式下epoll相当于一个效率较高的poll。
- ET(Edge Trigger,边沿触发)模式是epoll的高效工作模式。
2.poll
poll系统调用和select类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者。poll的原型如下:
#include <poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
- fds参数是一个pollfd结构类型的数组,它指定所有我们感兴趣的文件描述符上发生的可读、可写和异常等事件。pollfd结构体的定义如下:
struct pollfd { int fd; //文件描述符 short events; //注册的事件 short revents; //实际发生的事件,由内核填充 };
3.select
select的用途:在一段指定时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等事件。
#include <sys/select.h>
int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);
其中:
- nfds参数指定被监听的文件描述符的总数。
- readfds,writefds,exceptfds参数分别指向可读、可写和异常等事件对应的文件描述符。
- timeout参数用来设置select函数的超时时间。如果timeout传递NULL,则select将一直阻塞,直到某个文件描述符就绪。
系统调用 | select | poll | epoll |
---|---|---|---|
事件集合 | 用户通过3个参数 分别传入感兴趣的 可读、可写及异常 等事件,内核通过 对这些参数的在线 修改来反馈其中的 就绪事件。这使得 用户每次调用select 都要重置这 3个参数 |
统一处理所有事件 类型,因此只需 一个事件集参数。用 户通过pollfd.events 传入感兴趣的事件, 内核通过修改 pollfd.revents反馈 其中就绪的事件 |
内核通过一个事件表 直接管理用户感兴趣的 所有事件。因此每次 调用epoll_wait时, 无须反复传入用户感 兴趣的事件。epoll_wait 系统调用的参数events 仅用来反馈就绪的事件 |
应用程序索引 就绪文件描述符 的时间复杂度 |
O(n) | O(n) | O(1) |
最大支持 文件描述符数 |
一般有最大值限制,1024或2048 | 65535 | 65535 |
工作模式 | LT | LT | LT,同时支持ET高效模式 |
内核实现 和工作效率 |
采用轮询方式来 检测就绪事件, 算法时间复杂度为 O(n) |
采用轮询方式 来检测就绪事件, 算法时间复杂度为 O(n) |
采用回调方式来 检测就绪事件, 算法时间复杂度为 O(1) |