epoll 使用示例
epoll 使用示例
epoll 是 Linux 内核提供的一种高效的 I/O 多路复用机制,用于监控多个文件描述符(如套接字)的状态变化(可读、可写、异常等)。它是 select 和 poll 的改进版本,特别适合处理高并发场景下的网络连接。
为什么需要 epoll?
- 传统的 select 和 poll 在处理大量文件描述符时存在性能瓶颈:
- 线性扫描所有描述符:每次调用都需要遍历所有被监控的描述符,时间复杂度为 O(n)。
- 重复传递监控列表:每次调用需将监控的 fd 集合从用户态拷贝到内核态。
- 无法动态修改监控列表:每次调用需重新设置需监控的 fd。
- epoll 时间复杂度优化为 O(1)!
适用场景
- 高并发服务器(如 Web 服务器、游戏服务器、实时通信系统)。
- 需要同时管理数千甚至数万个网络连接的场景。
- 需要低延迟和高吞吐量的网络应用。
示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <sys/timerfd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
int main(int ac, char *av[]) {
int timerfd;
int epollfd;
struct epoll_event ev;
struct epoll_event new_ev;
struct itimerspec timer_value;
/* set timerfd */
timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timerfd < 0) {
printf("failed to create timer fd\n");
exit(1);
}
bzero(&timer_value, sizeof(timer_value));
timer_value.it_value.tv_sec = 1;
timer_value.it_value.tv_nsec = 0;
timer_value.it_interval.tv_sec = 1;
timer_value.it_interval.tv_nsec = 0;
/* set events */
epollfd = epoll_create1(0);
ev.events = EPOLLIN;
ev.data.fd = timerfd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &ev);
/* start timer */
if (timerfd_settime(timerfd, 0, &timer_value, NULL) < 0) {
printf("could not start timer\n");
exit(1);
}
/* wait for events */
while (1) {
int num_events = epoll_wait(epollfd, &new_ev, 1, 0);
if (num_events > 0) {
int timers_elapsed = 0;
(void) read(new_ev.data.fd, &timers_elapsed, 8);
printf("timers elapsed: %d\n", timers_elapsed);
}
}
struct itimerspec disarm = { 0 };
timerfd_settime(timerfd, 0, &disarm, NULL);
epoll_ctl(epollfd, EPOLL_CTL_DEL, timerfd, NULL);
close(timerfd);
close(epollfd);
exit(0);
}
本文由作者按照 CC BY 4.0 进行授权