poll() 无限期等待,尽管指定了超时

poll() waits indefinitely although timeout is specified

我正在编写一个 C 客户端-服务器程序,其中客户端必须从服务器接收大量数据。因为我希望我的客户端在服务器出现问题时不要无限期地等待 recv()(例如,发送数据时它停止了),所以我选择使用 poll() 中指定的函数linux man page.

我的代码如下所示:

while (...)
{
  struct pollfd fds;
  fds.fd = sock;
  fds.events = POLLIN;

retry:
  r = poll(&fds, 1, TIMEOUT*1000);
  if (r == -1 && errno == EINTR)
    goto retry;
  else if (r == -1)
    err_sys("poll() failed");
  else if (r == 0)
    err_sys("timeout expired");

  recv(...)
}

其中 sock 是与套接字关联的文件描述符,TIMEOUT 设置为 5 秒,我指定 POLLIN 作为事件,因为我对读取数据感兴趣。

问题

根据男人的说法:

The timeout argument specifies the number of milliseconds that poll() should block waiting for a file descriptor to become ready. The call will block until either:

   (1)  a file descriptor becomes ready;

   (2)  the call is interrupted by a signal handler; or

   (3)  the timeout expires.

但是,程序会无限期地阻塞在 poll() 函数上,即使在我停止服务器后超时已过期(我使用了 valgrind)。我还尝试将事件设置为 POLLIN | POLLPRI(为了捕捉一些异常情况),但它没有用。我多次阅读文档,但我无法弄清楚是什么导致了这个问题。

其他信息

我正在使用 Xubuntu 18.04,gcc 版本 7.4.0,目标 x86_64

即使没有数据可读,您的代码也会无条件调用 recv()。事实上,如果 poll() 不是 return 和 error/timeout.

,那么您完全忽略了 fds.revents 字段

您的循环应该更像这样:

struct pollfd fds;
fds.fd = sock;
fds.events = POLLIN;

do {
  r = poll(&fds, 1, TIMEOUT*1000);
  if (r == -1) {
    if (errno == EINTR) continue;
    perror("poll() failed");
    break;
  }
  else if (r == 0) {
    printf("timeout expired");
    break;
  }
  else if (fds.revents & POLLIN) {
    r = recv(...);
    if (r < 0) {
      perror("recv() failed");
      break;
    }
    else if (r == 0) {
      printf("socket disconnected\n");
      break;
    }
    else {
      // process data as needed...
    }
  }
  else if (fds.revents & (POLLERR | POLLNVAL)) {
    printf("socket error\n");
    break;
  }
}
while (1);

close(sock);