Почему select() всегда истекает? (окна)

Я использую select, чтобы попытаться дождаться подтверждения от другого хоста в сети, но он всегда возвращает 0. Я видел другие потоки с похожими вопросами, и их проблема всегда в том, что они не сбрасывают fd_set, или они не передают правильное значение для первого параметра select(). Это не может быть причиной моей проблемы, потому что я сбрасываю fd_set, и первый параметр игнорируется в Windows, по-видимому, согласно msdn.

while(!done)
{
    //send acknowledgment and sequence number
    sendto(_clientSocket, buff, 2, 0, (LPSOCKADDR)&_sockAddr, sizeof(SOCKADDR));

    //wait for acknowledgment
    struct timeval timeout;
    timeout.tv_sec = _rttInfo.timeout/1000;
    timeout.tv_usec = _rttInfo.timeout * 1000;

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(_clientSocket, &fds);

    //wait for client to send an acknowledgement
    //wait for the socket to be ready for reading
    int res = select(0, &fds, NULL, NULL, &timeout);
    int err = WSAGetLastError();

    if(res == 0) //if timed out, retry
    {
        timedOutCount++;
        if(timedOutCount >= MAX_TIMEOUTS)
        {
            cout << "Handshaking complete _" << endl;
            return true;
        }
        else
        {
            cout << "Acknowledgement timed out, resending sequence number and acknowledgement" << endl;
            continue;
        }
    }

// есть еще что-то, если заявления внизу, но это никогда не идет туда

Независимо от того, что в этот момент он возвращает 0. Я видел, как клиент и сервер отправляли информацию друг другу через сокет, поэтому я не думаю, что отправляю по неправильному адресу на стороне клиента. Вот код на стороне клиента для отправки того пакета, который ожидает select ():

buff[0] = _seqNum;
res = sendto(_socket, buff, 2, 0, (LPSOCKADDR) &sa_in, sizeof(SOCKADDR));

Я не могу быть единственным, кто когда-либо имел эту проблему, кто-нибудь знает, как решить эту проблему?

Изменить: Кто-то спросил, где заполняется _sockAddr, поэтому я включу это здесь: Где-то там создается экземпляр класса ClienThread, и вы можете видеть, как передается sockaddr_in.

while(true)
{
    try
    {
        // Wait for connection
        cout << "Waiting for incoming connection... ";

        sockaddr_in clientSockAddr;
        //  int clientSockSize = sizeof(clientSockAddr);

        // Listen in on the bound socket:
        //  hClientSocket = accept(hSocket,
        //  reinterpret_cast<sockaddr*>(&clientSockAddr),
        //  &clientSockSize);
        unsigned char seqNum = 0; 

        int addrSize = sizeof(clientSockAddr);
        //wait for a connection
        int res=0;

        //loop until we get a packet that's from someone new
        bool blocking = true;

        while(blocking)
        {
            res = recvfrom(hSocket, buff, strlen(buff), 0, (LPSOCKADDR)&clientSockAddr, &addrSize);         
            bool foundMatch = false;
            //check if we're already handling this client. If so, keep blocking. Otherwise, break out of the loop
            for(list<ClientThread*>::iterator it = clientList.begin(); it != clientList.end(); it++)
            {
                //compare network addresses
                if((*it)->GetSockAddr().sin_addr.S_un.S_addr == clientSockAddr.sin_addr.S_un.S_addr)
                {
                    foundMatch = true; 
                    break;
                }
            }
            if(!foundMatch)
            {
                blocking = false;
            }
        }
        err =  WSAGetLastError();  


        // Check if we can create a new client thread
        if(res != SOCKET_ERROR && res != 0)
        {
            seqNum = (unsigned char) buff[0]; //get the sequence number for handshaking
            cout << "accepted connection from: " << GetHostDescription(clientSockAddr) << endl;
            //start a client thread, to handle requests from this client.
            ClientThread* pThread = new ClientThread(hSocket, clientSockAddr, this, seqNum);
            clientList.push_back(pThread);
            pThread->start(); 
        }
    //  if (hClientSocket==INVALID_SOCKET)
    //      throw "accept function failed.";
    }
    catch(char* ex)
    {
        cerr << "\nError: " << ex << endl;
        bSuccess = false; 
    }

}

Edit2: после дальнейшей отладки я обнаружил, что вызовы sendto достигают намеченной цели, поскольку сообщения принимаются с вызовами recvfrom, а не с select. Однако мне нужно иметь возможность использовать неблокирующий вызов.

3 ответа

sendto() Вероятно, сбой, но вы не проверяете его на наличие ошибок. sizeof(SOCKADDR) неправильно использовать в последнем параметре. использование sizeof(_sockAddr) вместо:

if (sendto(_clientSocket, buff, 2, 0, (LPSOCKADDR)&_sockAddr, sizeof(_sockAddr)) == SOCKET_ERROR)
{
    cout << "Handshaking failed, error " << WSAGetLastError() << endl;
    return false;
}

Убедитесь, что ваш _sockAddr переменная является действительной sockaddr_in, sockaddr_in6, или же sockaddr_storageНЕ sockaddr,

На отдельной ноте, предполагая _rttInfo.timeout выражается в миллисекундах, ваш timeout.tv_usec значение рассчитывается неправильно. Вместо этого должно быть так:

struct timeval timeout;
timeout.tv_sec = _rttInfo.timeout / 1000;
timeout.tv_usec = (_rttInfo.timeout % 1000) * 1000;

Как и ожидалось, выберите время ожидания, потому что вы запрашиваете время ожидания (в зависимости от того, какое значение содержит rttInfo). Если вы хотите подождать дольше, настройте rttInfo, или если вы хотите подождать, пока что-то не произойдет, укажите нулевое значение для тайм-аута.

Выберите время ожидания, потому что вы установили время ожидания. Если вы хотите, чтобы операции блокировки блокировались, время ожидания должно быть нулевым: http://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx

Как вы сказали, первый параметр, кажется, игнорируется. Что-то на линии:

int res = select(0, &fds, NULL, NULL, NULL);
Другие вопросы по тегам