【发布时间】:2016-01-27 16:36:48
【问题描述】:
我有以下代码摘录(经过大量编辑以删除不重要的细节)在极少数特定情况下失败。
struct epoll_event *events = calloc(MAXEVENTS+1, sizeof(struct epoll_event));
struct sockaddr_in in_addr;
socklen_t in_len = sizeof in_addr;
while(1)
{
int n = epoll_wait(efd,events, MAXEVENTS, -1);
for(int i=0; i<n; i++)
{
struct epoll_event *evI = &events[i];
uint64 u64 = evI->data.u64;
int type = u64>>32, fd=u64, fdx = fd;
if(type == -1)
{
while((fd = accept4(fdx, &in_addr, &in_len, SOCK_NONBLOCK|SOCK_CLOEXEC))>-1)
{
setNew_Connection(efd, fd);
storeAddrPort(fd, &in_addr, &in_len);
}
}
else
{
if(evI->events&(EPOLLERR|EPOLLHUP|EPOLLRDHUP)){closeConnection(fd);}
if(evI->events&EPOLLOUT) //process out data stuff
else if(evI->events&EPOLLIN) //process in data stuff and possibly close a different connection.
}
}
}
监听套接字由evI->data.u64上部的-1区分
setNew_Connection 执行通常的接受操作,例如将新套接字添加到 epoll 等
使用EPOLLET。
现在一切正常,除了在以下情况下它会失败,因为events 只在epoll_wait 中更新,所以连接关闭不会影响n 事件,直到返回到while(1) 的顶部之后循环。
-
epoll_wait在事件结构表中使用 3 个排队的事件解除阻塞。 - 第一个事件 (n=0) 是传入数据,之后代码决定关闭不再需要的连接(例如文件描述符 8)。
- 第二个事件 (n=1) 是传入的新连接。
accept4分配 fd:8,因为它最近可用。setNew_Connection将其添加到 epoll 列表中。 - 第三个事件是第 2 步中关闭的连接的传入数据。即 fd:8 但它不再有效,因为原始 fd:8 连接已关闭,当前 fd:8 用于不同的连接。
我希望我已经充分解释了这个问题。问题是events 表中的排队事件在连接关闭时不会更新,直到代码返回到epoll_wait。我该如何解决这个问题?
【问题讨论】:
-
你可以将连接标记为关闭,并在事件处理程序之后做一个关闭循环。