Получить количество байтов, доступных в сокете, с помощью 'recv' с 'MSG_PEEK' в С++

С++ имеет следующую функцию для приема байтов из сокета, он может проверять количество байтов, доступных с помощью флага MSG_PEEK. С MSG_PEEK возвращаемое значение "recv" - это количество байтов, доступных в сокете:

#include <sys/socket.h>
ssize_t recv(int socket, void *buffer, size_t length, int flags); 

Мне нужно получить количество байтов, доступных в сокете, без создания buffer (без выделения памяти для buffer). Возможно ли и как?

Ответ 1

Вы ищете ioctl(fd,FIONREAD,&bytes_available) и под окнами ioctlsocket(socket,FIONREAD,&bytes_available).

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

Для этого обычно делается то, что вы просто читаете куски за раз, например

char buf[4096];
ssize_t bytes_read;
do {
     bytes_read = recv(socket, buf, sizeof(buf), 0);
     if (bytes_read > 0) {
         /* do something with buf, such as append it to a larger buffer or
          * process it */
     }
} while (bytes_read > 0);

И если вы не хотите сидеть там, ожидая данных, вы должны изучить select или epoll, чтобы определить, когда данные готовы к чтению или нет, а флаг O_NONBLOCK для сокетов очень если вы хотите, чтобы вы никогда не блокировали recv.

Ответ 2

В Windows вы можете использовать функцию ioctlsocket() с флагом FIONREAD, чтобы спросить у сокета, сколько байтов доступно, без необходимости читать/просматривать сами байты. Возвращаемое значение - это минимальное количество байтов recv(), которое может возвращаться без блокировки. К тому моменту, когда вы на самом деле вызываете recv(), может появиться больше байтов.