【发布时间】:2017-10-13 14:59:04
【问题描述】:
所以我有一些看起来像这样的代码:
for (;;) {
errno=0;
epoll_event e = {};
auto wait_r = epoll_wait(g.epoll_fd, &e, 1, 0);
if (wait_r==0) break;
if(wait_r ==-1 && errno==EINTR) {
printf("got EINTR\n");
continue;
}
assert(wait_r == 1);
auto& c = *(Context*)e.data.ptr;
if(e.events & EPOLLERR ) {
int error = 0;
socklen_t errlen = sizeof(error);
auto r1 =getsockopt(c.socket, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen);
assert(r1==0);
printf("Got EPOLLERR 2 %s\n", strerror(error));
}
if(e.events & EPOLLRDHUP || e.events & EPOLLHUP ) {
if (e.events & EPOLLRDHUP) {
printf("got to EPOLLRDHUP\n");
}
if (e.events & EPOLLHUP) {
printf("got to EPOLLHUP\n");
}
//continue; // keeps hitting this for same connections
break;
}
if (e.events & EPOLLIN) {
// Does a bunch of reads...
}
}
}
单个套接字将卡在EPOLLRDHUP || EPOLLHUP 案例中。套接字可能已关闭,当我尝试关闭它或执行 EPOLL_CTL_DEL 时,我得到一个 EBADFD。我的理解是 epoll 会自动摆脱任何死套接字,但情况似乎并非如此......有什么想法吗?
另一个可能的问题是,在套接字上,我正在使用 recvmsg/sendmsg,并且我正在通过这些套接字(它们是 unix 域流套接字)在进程之间发送文件描述符。我试图对其进行最终的 recvmsg,但也失败了......有什么想法吗?
【问题讨论】:
-
我建议您的代码在处理完
EPOLLHUP事件之前调用close。请注意,EPOLLHUP表示对方关闭了连接 - 但您的代码尚未关闭连接。由于fd仍然在您身边打开,epoll将继续轮询它。 -
@myst 当我尝试关闭它时,它会因文件描述符错误而失败,在这种情况下。但是感谢您对一般情况的建议。
-
我确定客户端
fd(不是g.epoll_fd)必须被您的代码关闭才能释放它的资源。您的代码不是一个完整的示例,因此我可以查看的数量是有限的。我不确定哪个函数调用会导致EBADFD或您传递给close的值。实际上,我什至不确定您将事件的fd值存储在哪里。您可以将它存储在事件中,但我有时会使用该事件来存储指向包含fd数据以及其他信息的对象的指针......并且可能会发生错误,因为您没有将它存储在任何地方。我说不出来。 -
@myst 好的,我正在为我的问题制作一个更好、更完整的最小示例。
-
@Myst 很抱歉让您久等了,但我最终想通了,请参阅下面的答案。我创建了我的代码的最小版本,但它没有出现问题,我很困惑一段时间,但现在解决方案似乎很明显......
标签: linux sockets network-programming epoll