epoll的手册页上有一个触发边的示例代码,如下所示:
for (;;) { nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_pwait"); exit(EXIT_FAILURE); } for (n = 0; n < nfds; ++n) { if (events[n].data.fd == listen_sock) { conn_sock = accept(listen_sock, (struct sockaddr *) &local, &addrlen); if (conn_sock == -1) { perror("accept"); exit(EXIT_FAILURE); } setnonblocking(conn_sock); ev.events = EPOLLIN | EPOLLET; ev.data.fd = conn_sock; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { perror("epoll_ctl: conn_sock"); exit(EXIT_FAILURE); } } else { do_use_fd(events[n].data.fd); } } }
在do_use_fd函数中,我在while循环中调用非阻塞recv直到EAGAIN为止,示例代码运行良好。
我对此示例代码有一个疑问,假设现在我有50个套接字客户端连接,突然有10个客户端同时写入数据,因此epoll_wait()将返回10,然后转到for循环:
for (n = 0; n < nfds; ++n)
它将调用 do_use_fd(events[n].data.fd); 这10个客户端,假设n = 5完成,并且n = 6尚未完成,则在所有这10个事件都完成之后,事件n = 3的文件描述突然接收到新数据,并返回epoll_wait ,该事件是否会通知我,有一个客户端需要读取新数据?否则我会错过它,因为当事件发生时,代码不在epoll_wait中!
do_use_fd(events[n].data.fd);
只要您一直阅读直到遇到EAGAIN错误,您下次调用时都会得到该事件epoll_wait。
EAGAIN
epoll_wait
仅当在空值和非空值之间(或的完整和不完整EPOLLOUT)之间发生更改时才触发该事件,但是该状态将保持不变,直到通过发送事件为止epoll_wait。
EPOLLOUT
有点相关的注释:如果您注册EPOLLIN和EPOLLOUT事件,并且假设您从未填满发送缓冲区,那么每次触发EPOLLOUT返回的事件中,您仍然会获得标志集- 请参见https://lkml.org/lkml/2011 / 11/17/234了解更多详细说明。epoll_wait``EPOLLIN
EPOLLIN
epoll_wait``EPOLLIN
最后,边沿触发模式的确切行为实际上取决于所使用的套接字类型,并且在任何地方都没有实际记载。我前段时间做了一些测试,并在这里记录了我的发现:http : //cmeerw.org/blog/753.html#753-简而言之,对于数据报套接字,您可能会收到比预期更多的事件。