1.1 epoll 默认设置
1.2 epoll Events
参考 epoll.h [1]
事件 | 简介 | 补充 |
---|
EPOLLIN | 文件描述符可读。 | 当有数据可读时触发该事件。 |
EPOLLPRI | 有紧急数据可读。 | 用于处理带外数据(out-of-band data)或优先级数据。 |
EPOLLOUT | 文件描述符可写。 | 当可以写入数据时触发该事件。 |
EPOLLRDNORM | 有普通数据可读。 | 类似于 EPOLLIN,用于读取操作。 |
EPOLLRDBAND | 有带外数据可读。 | 类似于 EPOLLPRI,用于处理带外数据。 |
EPOLLWRNORM | 可写入普通数据。 | 类似于 EPOLLOUT,用于写入操作。 |
EPOLLWRBAND | 可写入带外数据。 | 通常情况下不使用此事件。 |
EPOLLMSG | 有消息数据可读。 | 通常情况下不使用此事件。 |
EPOLLERR | 文件描述符发生错误。 | 当文件描述符发生错误时触发该事件。 |
EPOLLHUP | 文件描述符挂起。 | 当文件描述符的连接关闭时触发该事件。 |
EPOLLRDHUP | 文件描述符被远程关闭连接或半关闭连接。 | 在较新的内核版本中使用,旧版本使用 EPOLLHUP 来表示。 |
EPOLLEXCLUSIVE | 独占模式。 | 用于实现边缘触发(Edge Triggered)。 |
EPOLLWAKEUP | 唤醒等待的线程。 | 用于唤醒被 epoll_wait 阻塞的线程。 |
EPOLLONESHOT | 单次事件监听。 | 事件触发后需要重新添加到 epoll 集合中。 |
EPOLLET | 边缘触发模式。 | 边缘触发模式仅在文件描述符状态变化时通知一次,与水平触发模式不同。 |
warning
EPOLLEXCLUSIVE
: 可以用于缓解多进程共享的 socket 惊群问题。但是同一进程两次 epoll_wait 之间,如果有新的连接到来并被其他进程处理,当前进程仍旧会被唤醒。[2]
1.3 epoll 相关函数
epoll 在 kernel-6.4.1 中有 6 个函数,如下所示
1 2 3 4 5 6 7 8
| extern int epoll_create (int __size) __THROW; extern int epoll_create1 () extern int epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event) __THROW; extern int epoll_wait (int __epfd, struct epoll_event *__events, int __maxevents, int __timeout) extern int epoll_pwait () extern int epoll_pwait2 ()
|
1.3.1 基本操作
1.3.1.1 创建一个 epoll
实例:
1 2 3 4 5 6 7
|
int epollfd = epoll_create1(0); if (epollfd == -1) { perror("epoll_create1"); return EXIT_FAILURE; }
|
1.3.1.2 epoll_ctl 使用
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
#define DEFAULT_PORT 8080 #define MAX_EVENTS 10
int ret = 0;
int servfd = socket(AF_INET , SOCK_STREAM, 0); if (servfd == -1) { perror("socket error"); return -1 }
struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(DEFAULT_PORT);
ret = bind(servfd, (struct sockaddr*) &servaddr, sizeof(servaddr)); if (ret == -1) { perror("bind error"); return -1; }
ret = listen(servfd, 1024); if (ret == -1) { perror("listen error"); return -1 }
struct epoll_event ev; struct epoll_event events[MAX_EVENTS];
ev.event = EPOLLIN; ev.data.fd = servfd;
for (;;) { int nready = epoll_wait(epollfd, events, MAX_EVENTS, -1); if (nready == -1) { perror("epoll_wait error"); return -1; } for (int i = 0; i < nready; i++) { if (events[i].data.fd == servfd) { int connfd = accept(servfd, (struct sockaddr*) &cliaddr, &addrlen); if (connfd == -1) { perror("accept error"); return -1; } setnonblocking(connfd); ev.events = EPOLLIN | EPOLLET; ev.data.fd = connfd; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev) == -1) { perror("epoll_ctl: EPOLL_CTL_ADD error"); return -1; } } else { } } }
|
1.4 常见问题
1.5 引用
您正在使用不支持或禁用了 JavaScript 的浏览器访问我们的网站。
请考虑启用 JavaScript 以获得更好的浏览体验。
要访问真正的网站 "uocat.com",请手动复制以下网址并在您喜欢的浏览器中打开:
https://uocat.com