Select () иногда не ждет - PullRequest
       30

Select () иногда не ждет

0 голосов
/ 07 марта 2012

Я пишу программу чата, и моя функция приема иногда вообще не ждет .. Вот код получения: важные части - это в основном первая половина, но я добавил всю функцию на всякий случай. (Правка: комментирование для меня, а не для чтения, ребята, вы читаете! Извините!)

ReceiveStatus Server::Receive(PacketInternal*& packetInternalOut)
{
    fd_set fds ;
    int n ;
    struct timeval tv ;

    // Set up the file descriptor set.
    FD_ZERO(&fds) ;
    FD_SET(*p_socket, &fds) ;

    // Set up the struct timeval for the timeout.
    tv.tv_sec = NETWORKTIMEOUTSEC ;
    tv.tv_usec = NETWORKTIMEOUTUSEC ;

    // Wait until timeout or data received.
    n = select ( *p_socket, &fds, NULL, NULL, &tv ) ;
    if ( n == 0)
    { 
        return ReceiveStatus::ReceiveTimeout;
    }
    else if( n == -1 )
    {
        return ReceiveStatus::ReceiveSocketError;   
    }

    //need to make this more flexible so it can support others
    sockaddr_in fromAddr;
    int flags = 0;
    int fromLength = sizeof(fromAddr);

    char dataIn[TOTALPACKETSIZE];
    int bytesIn = recvfrom(*p_socket, dataIn, TOTALPACKETSIZE, flags, (SOCKADDR*)&fromAddr, &fromLength);
    // Convert fromAddr into ip, port
    if(bytesIn == SOCKET_ERROR)
    {
        return ReceiveStatus::ReceiveSocketError;
    }
    if(bytesIn > 0)
    {
        memcpy(packetInternalOut,dataIn,bytesIn);
        return ReceiveStatus::ReceiveSuccessful;
    }
    else
    {
        return ReceiveStatus::ReceiveEmpty;
    }

}

Есть ли что-то, что может повлиять на то, работает это или нет? моя программа чата может быть либо сервером, либо клиентом. они оба используют один и тот же код. Сервер в ожидании соединения сидит в Select () в течение 100 секунд, так как NETWORKTIMEOUTSEC = 100. Но в программе char, когда я хочу отправить сообщение, я сначала отправляю запрос на передачу, а затем жду Подтверждение (для пакета подтверждения мне нужно снова позвонить и получить). Теперь это шаг, который не ждет . моя функция ReceiveAck вызывает функцию Receive (), а прием выполняется прямо по всему коду. Я могу проверить это, создав клиент, а не сервер. Если я отправляю сообщение, где нет сервера, он должен подождать 100 секунд для подтверждения, а затем время ожидания. Но вместо этого, как только я нажимаю ввод, он говорит, что время истекло.

Я не могу понять, что заставило бы его пропустить этот шаг. Я отлаживал свою программу чата как в состоянии сервера, так и в состоянии клиента. Значения tv и fds одинаковы для обоих, но сервер будет ждать, а клиент не будет ...

Ответы [ 3 ]

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

Первый параметр select() равен на один больше последнего сокета.Итак, вам нужно:

n = select ( *p_socket + 1, &fds, NULL, NULL, &tv ) ;
0 голосов
/ 08 марта 2012

select() всегда следует использовать в цикле.Вы должны проверить его возвращение для трех условий:

  • -1 (ошибка), которые вы должны оценить, чтобы определить, является ли это смертельным.EINTR является примером нефатальной ошибки.
  • ноль, в этом случае некоторое неопределенное количество времени прошло, и, если вы заботитесь о том, сколько времени прошло, вынеобходимо проверить время отдельно.
  • Положительное значение, в этом случае вы должны проверить все помеченные дескрипторы и действовать на них.

Во всех случаях вы должны проверить,существуют любые другие условия, которые могут заставить вас выйти из цикла, например, сколько времени фактически прошло.

Обратите внимание, что первый параметр select() обычно должен быть константой FD_SETSIZE.Ничего не получится в настройке его на что-то еще.

Также обратите внимание, что только то, что вы получили дейтаграмму, не означает, что вы получили дейтаграмму, которую хотели.Вам нужен способ проверить, что вы не получили случайную дейтаграмму, которая случайно появилась в сети (это происходит).Вдоль этих строк убедитесь, что TOTALPACKETSIZE равно 65536, потому что это теоретически (приблизительно), насколько большим может быть случайный пакет.

0 голосов
/ 07 марта 2012

Select также возвращает рано (т. Е. При отсутствии данных в сокетах с данными), когда ваше приложение получает сигнал.Так что, если ваше приложение использует много usleep () и друзей в другой ветке, вас может удивить.

...