Winsock: функция recv - получение данных

Подскажите пожалуйста, в функции recv непонятен один момент:

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

Вроде все понятно, но:

std::string my_string_buff;
my_string_buff.resize(100);

int my_recv = recv(my_socket, &my_string_buff[0], my_string_buff.size(), 0);

Предположим я выделил буфер для приема из 100 байт и предположим сервер мне выслал сообщение равное именно 100 байтам, то есть я получил полностью все данные от сервера, НО так как я заранее размер получаемых данных не знаю, мне нужно вызвать recv еще раз и так как данные от севера уже получены, то второй вызов вернет 0, и по описанию - это будет означать, что сервер закрыл сокет, но это же не обязательно так! Если я общаюсь по http и попросил keep-alive, то сокет будет открыт, но функция recv все равно вернет 0, так как данных на данный момент нет.

И вот непонятно, как обрабатывать этот момент.


Ответы (2 шт):

Автор решения: gbg

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

У вас есть два-с половиной варианта управлять этой ситуацией - сделать сокет асинхронным, и тогда вы получите отрицательное значение, а в errono будет что-то типа EAGAIN (EWOULDBLOCK) - так система вам намекнет, что данных для вас у нее нет.

Половина варианта, доступная на линуксе - сделать не весь сокет неблокирующим, а только данную операцию, подставив флаг MSG_NONBLOCK

И еще вариант - перед чтением проверять, что в сокет что-то пришло. Это всякие poll, select и их вариации.

→ Ссылка
Автор решения: Fat-Zer

то второй вызов вернет 0, и по описанию - это будет означать, что сервер закрыл сокет, но это же не обязательно так!

Это не так. По умолчанию recv() будет ждать пока данные не появятся. Также он может вернуть -1, если сокет находится в неблокирующем режиме и данные ещё не пришли или вызов будет прерван сигналом с установкой соответствующий ошибки EAGAIN или EINTR.

Возврат нуля для tcp-сокета в невырожденной ситуации — это надёжный признак закрытия соединения второй стороной.

ЗЫ: Также стоит помнить, что с прикладной точки зрения TCP представляет из себя поток байт. Разделение его на сообщения следует делать по средствам протоколов более высоких уровней. Как именно — уже писал здесь.

→ Ссылка