использование select() для обнаружения закрытия соединения

Как описано в других сообщениях, я пытаюсь использовать select() в программировании сокетов для обнаружения закрытых соединений. См. следующий код, который пытается обнаружить закрытые соединения с помощью select(), и последующую проверку того, возвращает ли recv() 0. Перед запуском цикла while уже есть два установленных TCP-соединения. В нашем контролируемом эксперименте первое соединение всегда закрывается примерно через 15 секунд, а второе — примерно через 30 секунд.

Теоретически (как описано другими), когда они закрываются, select() должен возвращаться (дважды в нашем случае), что позволяет нам обнаруживать оба события закрытия. Проблема, с которой мы сталкиваемся, заключается в том, что select() теперь возвращается только один раз и никогда больше, что позволяет нам обнаруживать ТОЛЬКО первое событие закрытия соединения. Если код для одного IP работает нормально, но не для двух и более подключений.

У кого-нибудь есть идеи или предложения? Спасибо.

while (1)
   {
      printf("Waiting on select()...\n");
      if ((result = select(max + 1, & readset, NULL, NULL, NULL)) < 0)
      {
         printf("select() failed");
         break;
      }
      if (result > 0)
      {
        i=0;
        while(i<max+1) 
        {
          if (FD_ISSET(i, &readset)) 
          { 
            result = recv(i, buffer, sizeof(buffer), 0);
            if (result == 0) 
               {
                  close(i);
                  FD_CLR(i, &readset);
                  if (i == max)
                  {
                     max -= 1;
                  }
               }
          }
      i++;
        }
     }
  }

person User    schedule 03.01.2015    source источник


Ответы (1)


select() модифицирует readset для удаления сокетов, которые не доступны для чтения. Каждый раз, когда вы вызываете select(), вы должны сбросить и заполнить readset своим последним списком активных сокетов, которые вы хотите протестировать, например:

fd_set readset;
int max;

while (1)
{
    FD_ZERO(&readset);
    max = -1;

    // populate readset from list of active sockets...
    // set max according...

    printf("Waiting on select()...\n");
    result = select(max + 1, &readset, NULL, NULL, NULL);
    if (result < 0)
    {
       printf("select() failed");
       break;
    }

    if (result == 0)
        continue;

    for (int i = 0; i <= max; ++i)
    {
        if (FD_ISSET(i, &readset)) 
        { 
          result = recv(i, buffer, sizeof(buffer), 0);
          if (result <= 0) 
          {
              close(i);
              // remove i from list of active sockets...
          }
      }
   }
}
person Remy Lebeau    schedule 04.01.2015