【问题标题】:How to update epoll events after epoll_wait?如何在 epoll_wait 之后更新 epoll 事件?
【发布时间】: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-&gt;data.u64上部的-1区分

setNew_Connection 执行通常的接受操作,例如将新套接字添加到 epoll 等

使用EPOLLET

现在一切正常,除了在以下情况下它会失败,因为events 只在epoll_wait 中更新,所以连接关闭不会影响n 事件,直到返回到while(1) 的顶部之后循环。

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

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

【问题讨论】:

  • 你可以将连接标记为关闭,并在事件处理程序之后做一个关闭循环。

标签: c events epoll


【解决方案1】:

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

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];
  }

【讨论】:

    猜你喜欢
    • 2018-10-28
    • 2011-06-21
    • 1970-01-01
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 2022-01-06
    相关资源
    最近更新 更多