Завершение цикла "recv ()", когда вся информация читается с использованием Winsock - PullRequest
6 голосов
/ 27 июля 2010

У меня проблема в цикле recv () для winsock. Я пытаюсь завершить цикл, когда iResult == 0, однако цикл заканчивается только тогда, когда сокет закрывается. Похоже, что он зависает в самом последнем recv (), где iResult будет равен 0. Итак, есть ли идеи о том, как эффективно завершить цикл? Моя конечная цель (iResult == 0 или нет; возможно, я поступаю неправильно) остановить цикл, когда вся отправленная информация будет прочитана. Вот петля.

    do
    {
        iResult = recv(socket, recvbuf, BUFLEN-1, 0);
        if(iResult > 0){
            // Null byte :)
            // Remove that garbage >:(
            recvbuf[iResult] = '\0';
            printf("Recvbuf: %s\n\n\niResult: %d\n",recvbuf,iResult);
            continue; // working properly
        }
        else if(iResult == 0)
            // Connection closed properly
            break;
        else
        {
            printf("ERROR! %ld",WSAGetLastError());
            break;
        }
    } while(iResult > 0);

Как я уже сказал, я получаю все данные, я просто не могу выйти из цикла. Следующим шагом будет запись данных обратно на сервер, но он зависнет здесь до истечения времени ожидания ping. Сокет SOCK_STREAM, а BUFLEN определяется как 0x200

.

Спасибо

Ответы [ 2 ]

4 голосов
/ 27 июля 2010

По умолчанию вместо возврата 0 блоки recv , если нет данных для приема :

Если в сокете нет входящих данных, вызов recvблокирует и ожидает поступления данных в соответствии с правилами блокировки, определенными для WSARecv с установленным флагом MSG_PARTIAL, если сокет не является неблокирующим.В этом случае возвращается значение SOCKET_ERROR с кодом ошибки, установленным в WSAEWOULDBLOCK.Функции select, WSAAsyncSelect или WSAEventSelect могут использоваться для определения того, когда поступает больше данных.

Вы можете использовать ioctlsocket , чтобы перевести сокет в неблокирующий режим:

u_long iMode = 1;
ioctlsocket(socket, FIONBIO, &iMode);

РЕДАКТИРОВАТЬ : Вот предложение setsockopt, которое я сделал в более ранней версии, затем удалил (см. Комментарии):

Вы можете использовать setsockoptФункция с опцией SO_RCVTIMEO для установки времени ожидания сокета на recv, если данные недоступны.

1 голос
/ 27 июля 2010

При разработке механизма связи TCP вы должны определить границы сообщения. (часто \ r \ n). Сам по себе tcp не знает о границах; Вы должны сделать это самостоятельно. Вызов recv () может не всегда возвращаться на границе сообщения. Один send () может быть разбит на несколько recv () с другого конца.

...