epoll_wait后如何更新epoll事件?

How to update epoll events after epoll_wait?

我有以下代码摘录(经过大量编辑以删除不重要的细节)在极少数情况下会失败。

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) 循环的顶部。

  1. epoll_wait 解除阻塞,事件结构 table.
  2. 中有 3 个事件排队
  3. 第一个事件 (n=0) 是传入数据,之后代码决定关闭连接(例如文件描述符 8),因为不再需要它。
  4. 第二个事件 (n=1) 是传入的新连接。 accept4 分配 fd:8,因为它最近可用。 setNew_Connection 将其添加到 epoll 列表中。
  5. 第三个事件是在步骤 2 中关闭的连接的传入数据。即 fd:8 但它不再有效,因为原始 fd:8 连接已关闭,当前 fd:8 是用于不同的连接。

我希望我已经充分解释了这个问题。问题是 events table 中的排队事件在连接关闭时不会更新,直到代码 returns 到 epoll_wait。我如何编写代码来解决这个问题?

Orel 给了我答案,但我想我会 post 完整的代码解决方案。而不是

close(fd)

我用

shutdown(fd,SHUT_RDWR);
FDS[FDSL++] = fd;

shutdown 阻止了更多数据的读取或写入,但实际上并没有关闭套接字。 FDS[FDSL++] = fd; 存储 fd,以便稍后在 n 个事件完成后,可以使用 while(FDSL)close(FDS[--FDSL];

关闭它
int FDS[MAXEVENTS],FDSL=0;

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.
      }
    }

  while(FDSL)close(FDS[--FDSL];
  }