C / C ++ сокеты и неблокирующая функция recv () - PullRequest
12 голосов
/ 13 июня 2011

У меня проблема, когда системный вызов recv () не блокируется. В данный момент у меня настроена структура клиент-сервер, и проблема, с которой я сталкиваюсь, заключается в том, что я отправляю серверу одно сообщение, пока сервер настроен так, что он выглядит примерно так:

while (1) {
   char buf[1024];
   recv(fd, buf, sizeof(buf), flags);
   processMsg(buf);
}

Он получает первое сообщение правильно, но recv () не блокирует и «получает» данные корзины, которые не являются желаемыми. Я хотел бы реагировать на сообщения только тогда, когда они отправлены. Кто-нибудь может посоветовать?

Ответы [ 3 ]

13 голосов
/ 13 июня 2011

recv () не обязательно блокируется, пока не будет выполнен полный запрос, но может вернуть частичный запрос.Код возврата сообщит вам о том, сколько байтов было фактически получено, что может быть меньше, чем вы запрашивали.Даже если вы укажете флаг MSG_WAITALL, он может вернуть меньше из-за сигнала и т. Д.

В системах posix в режиме блокировки recv будет блокировать только до тех пор, пока не будут представлены некоторые данные для чтения.Затем он вернет эти данные, которые могут быть меньше запрошенных, вплоть до запрошенной суммы.В неблокирующем режиме recv немедленно вернется, если есть нулевые байты данных для чтения, и вернет -1, установив errno в EAGAIN или EWOULDBLOCK.

В результате обычно вы будете вызывать recv в циклепока вы не получите нужную сумму, а также проверьте коды возврата 0 (другая сторона отключена) или -1 (некоторая ошибка).

Я не могу говорить о поведении окон.

12 голосов
/ 13 июня 2011

Есть две возможности: либо происходит ошибка, либо сокет установлен в неблокирующий режим.Чтобы увидеть, происходит ли ошибка, проверьте возвращаемое значение recv:

while() {
    char buf[1024];
    int ret = recv(,buf,,)

    if(ret < 0) {
        // handle error
        printf("recv error: %s\n", strerror(errno));
    } else {
        // only use the first ret bytes of buf
        processMsg(buf, ret);
    }
}

Чтобы перевести сокет в неблокирующий режим или запросить, находится ли сокет в неблокирующем режиме, используйтеfcntl(2) с флагом O_NONBLOCK:

// Test if the socket is in non-blocking mode:
if(fcntl(sockfd, F_GETFL) & O_NONBLOCK) {
    // socket is non-blocking
}

// Put the socket in non-blocking mode:
if(fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK) < 0) {
    // handle error
}

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

1 голос
/ 13 июня 2011

Если вы работаете в Windows, запустите функцию wsagetlasterror () и посмотрите возвращаемое значение.

http://msdn.microsoft.com/en-us/library/ms741580%28v=vs.85%29.aspx

Если вы работаете в системе, поддерживающей posix, посмотрите на errno

http://pubs.opengroup.org/onlinepubs/009695399/functions/errno.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...