当套接字关闭时,epoll 不会发出事件信号

epoll does not signal an event when socket is close

我有一个侦听器套接字,我得到的每个新连接都会像这样将它添加到 epoll:

int connfd = accept(listenfd, (struct sockaddr *)&clnt_addr, &clnt_addr_len);
ev.events = EPOLLIN | EPOLLET | EPOLLONESHOT | EPOLLHUP;
ev.data.fd = connfd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev)

收到新数据时,epoll 信号 'EPOLLIN' 事件 - 正如预期的那样。

遇到这样的情况,我查阅了全部资料如下:

long read = 0;
do {
    read = recv(events[n].data.fd, buffer, sizeof (buffer), 0);
} while (read > 0);

如果我粗暴地或正常地断开连接,epoll 不会发出事件信号。

每个线程中的代码运行,这就是我正在使用的 EPOLLET。

所以我的问题是:

  1. 我需要做什么才能获得此活动?
  2. 我需要怎么做才能关闭socket才不会造成资源泄露?

您的尝试存在一些问题。

  1. 你不应该使用 EPOLLONESHOT 除非你知道你在做什么并且你真的需要它。它会禁用向 epoll 实例报告任何其他事件,直到您使用 EPOLL_CTL_MOD.

    再次启用它为止
  2. 您不应使用 EPOLLHUP 来确定连接是否已关闭。 EPOLLHUP 事件可能会在从套接字输入流中读取所有数据之前引发,即使客户端正常断开也是如此。我建议你只使用 EPOLLIN。如果没有剩余输入(因为强制或正常断开连接),read() 将 return 0 (EOF) 并且您可以关闭套接字。

  3. 您的 read() 调用将阻塞读取线程并消耗整个流,直到 EOF(连接关闭)。使用 epoll() 的重点是不必使用 while ( read(...) > 0 ) 循环。

  4. 您不应该使用 EPOLLET,因为“代码 运行 是多线程的”,而是因为您需要它。您可以在没有 edge-triggered 模式的情况下编写多线程代码。使用 EPOLLET 需要透彻了解阻塞和 non-blocking I/O 之间的区别。您很容易 运行 陷入陷阱(如手册中所述),例如 edge-triggered 饥饿。