设置 epoll
创建并注册 epoll 集合。
设置 epoll 是 CoddyKit 上的免费 C Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。
创建 epoll 实例
一切都从 epoll 实例开始,它本身就是一个文件描述符。请使用 epoll_create1() 创建它。
该参数是一个标志字段;传入 0 可使用默认行为,传入 EPOLL_CLOEXEC 则可在跨 exec() 时自动关闭该描述符。返回的 fd 将用于传递给其他所有 epoll 调用。
int epfd = epoll_create1(EPOLL_CLOEXEC);
if (epfd == -1) { perror("epoll_create1"); exit(1); }epoll_create1 与 epoll_create
较早的 epoll_create(int size) 接受一个大小提示,但内核现在会忽略它;唯一的要求是该值必须为正数。
建议优先使用 epoll_create1():它接受标志而不是没有实际意义的大小,并且允许您以原子方式请求 EPOLL_CLOEXEC,从而避免单独调用 fcntl()。
/* legacy form, size arg ignored by kernel */
int epfd = epoll_create(1);epoll_event 结构体
关注的事件和返回的结果都通过 struct epoll_event 表示。它包含一个 events 位掩码和一个 data 联合体。
data 联合体保存事件触发时您希望获得的内容:通常是 data.fd,但也可以是指向您分配的连接对象的 data.ptr。
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = listen_fd;使用 EPOLL_CTL_ADD 注册
epoll_ctl() 管理关注列表。请使用 EPOLL_CTL_ADD 操作开始监视一个描述符。
您需要传入 epoll fd、操作、目标 fd,以及指向 epoll_event 的指针。完成后,epoll 将报告该描述符是否已就绪。
struct epoll_event ev = { .events = EPOLLIN, .data.fd = listen_fd };
if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev) == -1)
perror("epoll_ctl: add");事件标志:EPOLLIN 与 EPOLLOUT
events 掩码表示您关注的内容。EPOLLIN 表示描述符可读;EPOLLOUT 表示描述符可写。
通常会在监听套接字上监视 EPOLLIN(以接受连接),在客户端套接字上监视 EPOLLIN(以读取数据)。只有存在尚未完全发送的缓冲数据时,才添加 EPOLLOUT。
ev.events = EPOLLIN | EPOLLOUT;错误与挂断标志
即使您没有请求,内核也始终会报告某些状态:EPOLLERR 表示错误,EPOLLHUP 表示挂断,EPOLLRDHUP 表示对端半关闭。
请在处理程序中检查这些标志;忽略已失效套接字上的 EPOLLHUP 会导致事件循环不断空转。
if (ev.events & (EPOLLERR | EPOLLHUP)) {
close(ev.data.fd);
continue;
}使用 EPOLL_CTL_MOD 修改关注项
描述符注册后,您可以在不移除它的情况下更改其事件掩码。请使用 EPOLL_CTL_MOD。
一种常见模式是:连接通常只监视 EPOLLIN;当发送缓冲区填满时,切换为 EPOLLIN | EPOLLOUT,缓冲区刷新完毕后再切回。
ev.events = EPOLLIN | EPOLLOUT;
ev.data.fd = conn_fd;
epoll_ctl(epfd, EPOLL_CTL_MOD, conn_fd, &ev);使用 EPOLL_CTL_DEL 移除
连接关闭时,请使用 EPOLL_CTL_DEL 停止监视它。最后一个 epoll_event 参数会被忽略,在现代内核中可以是 NULL。
请注意,关闭描述符会自动将其从所有 epoll 关注列表中移除,但在关闭前显式删除可以让您的状态记录更加清晰。
epoll_ctl(epfd, EPOLL_CTL_DEL, conn_fd, NULL);
close(conn_fd);水平触发与边沿触发
默认情况下,epoll 使用水平触发:只要描述符保持可读,每次 epoll_wait() 都会报告它。这种方式宽容且易于使用。
添加 EPOLLET 标志可启用边沿触发模式:只有就绪状态发生变化时才会收到通知,因此您必须循环读取套接字,直到返回 EAGAIN,将数据完全读尽。
ev.events = EPOLLIN | EPOLLET; /* edge-triggered */
epoll_ctl(epfd, EPOLL_CTL_ADD, conn_fd, &ev);存储上下文指针
除了 data.fd,您还可以存储指向每个连接对应结构体的 data.ptr。事件触发时,您可以直接取回该指针,无需查找表。
但请记住联合体的特性:如果设置了 data.ptr,就不能同时从同一个事件中读取 data.fd。
struct conn *c = malloc(sizeof *c);
c->fd = conn_fd;
ev.events = EPOLLIN;
ev.data.ptr = c;
epoll_ctl(epfd, EPOLL_CTL_ADD, conn_fd, &ev);清理资源
epoll 实例只是一个文件描述符,因此服务器关闭时请使用 close() 释放它。
关闭 epoll fd 会释放内核的关注列表。任何仍处于打开状态的受监视套接字都会继续保持打开;请分别关闭它们以释放各自的资源。
close(epfd);快速检查
测试您对 epoll 设置 API 的掌握程度。
回顾
您可以使用 epoll_create1() 创建实例,然后通过 epoll_ctl() 使用 ADD、MOD 和 DEL 管理关注项。每个 struct epoll_event 都包含一个 events 掩码和一个 data 联合体。
为了简单易用,请选择水平触发;为了获得边沿触发的性能,请使用 EPOLLET。接下来,我们将在事件循环中驱动这些组件。
常见问题解答
「设置 epoll」课时是免费的吗?
是的 — 「设置 epoll」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。
「设置 epoll」这节课中我会学到什么?
创建并注册 epoll 集合。 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「设置 epoll」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C Academy 课中编写并运行代码吗?
能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 阻塞与非阻塞 I/O
- 设置 epoll
- 事件循环
- 简单的回显服务器