带边缘触发事件的epoll
epoll的手册页:
http://linux.die.net/man/7/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尚未完成,突然事件n = 3的文件描述已经接收到新数据,在所有10个事件完成并返回到epoll_wait后,I得到事件告诉我有一个客户有新的数据要读? 或者我会错过它,因为事件发生时,代码不在epoll_wait!
只要您阅读,直到您遇到EAGAIN
错误,您将在下一次调用epoll_wait
时获得该事件。
该事件仅在空和非空(或EPOLLOUT
满和非满)之间发生变化时触发,但该状态将保留,直到事件通过epoll_wait
。
在一个有点相关的注意事项:如果您注册了EPOLLIN
和EPOLLOUT
事件,并假设你从来没有填满发送缓冲区,你仍然可以获得EPOLLOUT
在返回的事件设置标志epoll_wait
每次EPOLLIN
触发-看到的是https:// LKML。 org / lkml / 2011/11/17/234获取更详细的解释。
最后,边缘触发模式的确切行为实际上取决于所使用的套接字类型,并且没有真正记录在任何地方。 我前段时间做了一些测试,并在此处记录了我的发现:http://cmeerw.org/blog/753.html#753 - 简而言之,对于数据报套接字,您可能会获得比预期更多的事件。
当你使用epoll下的边缘触发时,读一些东西,可以这样
int n = -1;
while (1)
{
n = recv(fd, iobuf, init_buff_size, MSG_DONTWAIT);
if (n > 0)
{
LOG(glogfd, LOG_TRACE, "fd[%d] recv len %dn", fd, n);
mybuff_setdata(&(curcon->recv_buff), iobuf, n); // this is my func
if (n == init_buff_size)
{
LOG(glogfd, LOG_DEBUG, "fd[%d] need recv nextloop %dn", fd, n);
continue;
}
break;
}
if (n == 0)
{
LOG(glogfd, LOG_ERROR, "fd[%d] close %s:%d!n", fd, ID, LN);
return do_close(fd);
}
if (errno == EINTR)
{
LOG(glogfd, LOG_TRACE, "fd[%d] need recv again!n", fd);
continue;
}
else if (errno == EAGAIN)
{
LOG(glogfd, LOG_TRACE, "fd[%d] need recv next!n", fd);
modify_fd_event(fd, EPOLLIN); // this is the KEY, add read again
break;
}
else
{
LOG(glogfd, LOG_ERROR, "fd[%d] close %s:%d!n", fd, ID, LN);
return do_close(fd);
}
}
链接地址: http://www.djcxy.com/p/61345.html