poll () ждет бесконечно, хотя таймаут указан - PullRequest
0 голосов
/ 08 мая 2019

Я пишу клиент-серверную программу C, в которой клиент должен получать большое количество данных с сервера.Поскольку я хочу, чтобы мой клиент не ожидал бесконечно долго на recv(), если с сервером что-то пойдет не так (например, он остановился при отправке данных), я решил использовать функцию poll(), как указано в linux Страница man .

Мой код выглядит примерно так:

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 как событие, так как меня интересует чтение данных.

Задача

По словам человека:

Аргумент timeout указывает количество миллисекунд, которые poll () должен блокировать в ожидании готовности дескриптора файла.Вызов будет блокироваться до:

   (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

1 Ответ

1 голос
/ 08 мая 2019

Ваш код безоговорочно вызывает recv(), даже если нет данных для чтения. Фактически, вы полностью игнорируете поле fds.revents, если poll() не возвращает ошибку / тайм-аут.

Ваш цикл должен выглядеть примерно так:

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);
...