Подтвердить что ты не робот

C/С++ и неблокирующий recv()

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

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

Существуют две возможности: либо ошибка, либо сокет установлен в неблокирующий режим. Чтобы узнать, произошла ли ошибка, проверьте возвращаемое значение 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
}

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