блокировка select () из нескольких сокетов - PullRequest
6 голосов
/ 06 марта 2012

Unix / C вопрос здесь.

У меня есть несколько сокетов, которые я пытаюсь опросить для периодических данных.Я не хочу выбирать ждать бесконечно, поэтому у меня есть тайм-аут, и я работаю в цикле.Я обнаружил, что когда сокет готов к чтению, всегда готов к чтению .Как и в случае, я не могу выбрать «идти спать», когда нет данных для чтения из любого из сокетов.

for (i = 0; i < n_connections; i++) {
  FD_SET( sockfd[i], &master );
  if (sockfd[i] > fdmax) 
    fdmax = sockfd[i];
  }

for(;;) {
  int nready = 0;
  timeout.tv_sec  = 1;
  timeout.tv_usec = 0;
  read_fds = master;
  if ( (nready = select(fdmax+1, &read_fds, NULL, NULL, NULL)) == -1 ) {
    fprintf( stderr, "Select Error\n" );
    return FAILURE;
  }
  printf( "Number of ready descriptors: %d\n", nready );

  for (i = 0; i <= fdmax; i++) {
    if (FD_ISSET(i, &read_fds)) {
      if (( nbytes = recv(i, buf, sizeof(buf), 0)) <= 0 ) {
        if (nbytes == 0) {
          //connection closed
          printf("Socket %d hung up\n", i );
        }
        else {
          fprintf( stderr, "Recv Error %d\n", nbytes);
        }
      }
    else {
      printf( "Data Received on %d: %s\n", i, buf );
    }
  }
} // end file descriptor loop

Кажется, что после моего первого чтения 1-секундный таймаут больше не применяется, и сокет всегда «готов к чтению», даже если доступно 0 байтов.Как я могу заставить select перейти в спящий режим до поступления данных (в течение одной секунды или путем переключения последнего аргумента на NULL, бесконечно ожидая поступления данных в сокет?)

Вывод:

Number of Ready Descriptors: 2
Data Received on 4: GreetingsChap
Data Received on 5: HiMatengsChap
Loop...
Number of Ready Descriptors: 2
Socket 4 hung up
Socket 5 hung up
Loop...
Number of Ready Descriptors: 2
Socket 4 hung up
Socket 5 hung up
Loop...

Спасибо,

Примечание: код обновлен для ясности Обновлен на основе предложений @yvesBraumes - все еще не работает.

Ответы [ 3 ]

6 голосов
/ 06 марта 2012

Если вы обнаружите, что соединение закрыто, удалите сокет из набора fd, в противном случае select сообщит о них (Socket 4 hung up) .. select не инициируется по краю, если вы не обрабатываете событие , он собирается сообщить об этом снова.

4 голосов
/ 16 марта 2012

Действительно, если recv возвращает 0 (а не -1, с errno = EWOULDBLOCK), сокет закрывается. Вы должны также позвонить на close() и убрать его из вызова select(). В противном случае он останется в WAIT1 и каждый раз будет выдавать select().

0 голосов
/ 07 ноября 2017

Вы используете FD_ISSET неправильно. Вам необходимо передать идентификатор сокета в параметр "fd", а не в индекс:

if (FD_ISSET(i, &read_fds))...

должно быть

if (FD_ISSET(sockfd[i], &read_fds))...

Аналогично с recv.

...