Linux--多路转接之epoll
上一篇:Linux–多路转接之select
epoll
epoll
是 Linux 下多路复用 I/O 接口 select/poll 的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统 CPU 利用率。它是 Linux 下多路复用 API 的一个选择,相比 select
和 poll
,epoll
提供了更高的性能,并且使用起来也更加方便。
epoll的工作原理
eventpoll框架的核心在于它能够高效地处理多个文件描述符上的事件,避免了传统I/O多路复用机制(如select和poll)中的轮询开销。eventpoll通过以下方式实现:
- 注册文件描述符:当文件描述符被注册到eventpoll时,会创建一个epitem(eventpoll item)结构体,用于表示该文件描述符及其关心的事件类型。这个epitem会被插入到eventpoll的红黑树(rbtree)中,以便快速查找和管理。
- 等待事件发生:通过调用epoll_wait()系统调用,应用程序会在eventpoll的等待队列(wq)上等待。此时,指定的回调函数是default_wake_function,用于在事件发生时唤醒等待的线程。
- 事件通知:当被监测的文件描述符上有事件发生时,会调用ep_poll_callback()回调函数,将相应的epitem插入到eventpoll的就绪链表(rdllist)中。epoll_wait()会从这个链表中取出epitem,并将对应的事件通知给应用程序。
注意:以上操作均有系统自主完成
epoll 的相关系统调用
epoll_create()
创建一个 epoll 的句柄.
#include
int epoll_create(int size);
size
参数用于告诉内核这个监听列表(epoll 实例)打算同时监视多少个文件描述符。
返回值:
如果调用成功,epoll_create 返回一个新的文件描述符,该描述符用于后续的 epoll_ctl()和 epoll_wait()调用。
如果调用失败,则返回 -1,并设置 errno 以指示错误原因。
epoll_ctl()
允许程序在 epoll 实例中添加、修改或删除文件描述符(file descriptors)的监听事件.
#include
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
参数说明
- epfd:由
epoll_create ()
函数生成的 epoll 实例的文件描述符。- op:指定要执行的操作,常用的值包括:
EPOLL_CTL_ADD
:向 epoll 实例注册新的文件描述符和事件。
EPOLL_CTL_MOD
:修改已注册的文件描述符的事件。
EPOLL_CTL_DEL
:从 epoll 实例中删除一个文件描述符。- fd:要操作的目标文件描述符,即要注册、修改或删除的文件描述符。
- event:指向 struct epoll_event 结构体的指针,该结构体包含了要注册或修改的事件信息。对于
EPOLL_CTL_DEL
操作,该参数可以为 NULL。
typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t; struct epoll_event { uint32_t events; /* 事件类型 */ epoll_data_t data; /* 与事件相关的数据 */ };
events:这是一个位掩码,用于指示发生的事件类型。常见的事件类型包括:
EPOLLIN
:表示对应的文件描述符可以进行读操作。
EPOLLOUT
:表示对应的文件描述符可以进行写操作。
EPOLLERR
:表示发生错误。
EPOLLHUP
:表示挂起(hang up)事件,比如对端关闭了连接。
EPOLLET
:将事件设置为边缘触发(Edge Triggered)模式,这是与水平触发(Level Triggered)模式相对的一种触发模式。
EPOLLONESHOT
:用于确保事件被触发一次后,除非再次使用 epoll_ctl 重新注册,否则不再接收该事件。data:这是一个联合体,可以存储与事件相关的数据。它提供了多种方式来关联事件和特定的数据或文件描述符:
ptr
:可以指向任意类型的数据,通常用于存储用户自定义的数据结构指针。
fd
:直接存储文件描述符的值,当只需要管理文件描述符时,这种方式更为直接(常用)。
u32
和u64
:分别提供了32位和64位的无符号整数存储,这些字段可以用来存储特定的值或标识符。
epoll_wait()
程序调用 epoll_wait 时,它会阻塞当前线程,直到注册在 epoll 实例上的文件描述符上有事件发生,或者超时时间到达。
#include
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
参数说明
epfd
:由epoll_create
函数生成的 epoll 实例的文件描述符。events
:指向struct epoll_event
数组的指针,用于存储发生的事件。当epoll_wait
返回时,该数组将被填充有发生事件的文件描述符和事件类型的信息。maxevents
:指定 events 数组的最大长度,即 epoll_wait 一次可以处理的最大事件数。timeout
:指定等待 I/O 事件发生的超时时间(毫秒)。如果设置为 -1,则epoll_wait
将无限期地等待,直到有事件发生。如果设置为 0,则 epoll_wait 将立即返回,无论是否有事件发生。如果设置为一个正整数,则 epoll_wait 将等待指定的毫秒数,如果在这段时间内有事件发生,则返回;否则返回 0,表示超时。
返回值
- 成功时,epoll_wait 返回发生事件的文件描述符数量。如果返回 0,则表示在指定的超时时间内没有事件发生。
- 如果发生错误,epo