如何在epoll_wait之后更新epoll事件?

时间:2015-10-28 02:38:17

标签: c events epoll

我有以下代码摘录(经过严格修改以删除不重要的细节),这些代码在罕见且特殊情况下失败。

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

-1

的上半部分evI->data.u64区分了听力套接字

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. 第3个事件是在步骤2中关闭的连接的传入数据,即fd:8,但它不再有效,因为原始fd:8连接已关闭,当前fd:8用于不同的连接。
  5. 我希望我已经充分解释了这个问题。问题是,在关闭连接之前,events表中的排队事件不会更新,直到代码返回到epoll_wait。我怎么能解决这个问题?

1 个答案:

答案 0 :(得分:0)

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