使用C ++中的'MSG_PEEK'获取'recv'中套接字可用的字节数

时间:2012-10-20 02:48:26

标签: c sockets buffer recv peek

C ++具有以下函数来从套接字接收字节,它可以检查MSG_PEEK标志可用的字节数。对于MSG_PEEK,返回的'recv'值是socket中可用的字节数:

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

我需要在不创建buffer的情况下获取套接字中可用的字节数(不为buffer分配内存)。它有可能吗?如何?

3 个答案:

答案 0 :(得分:31)

您正在寻找ioctl(fd,FIONREAD,&bytes_available),并在Windows 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);

如果您不想坐在那里等待数据,您应该查看selectepoll以确定何时可以读取数据,以及{{1}如果你想确保你永远不会阻止recv。} / socket for socket是非常方便的。

答案 1 :(得分:2)

在Windows上,您可以使用ioctlsocket()函数和FIONREAD标志来询问套接字可用的字节数,而无需读取/查看实际字节本身。返回的值是recv()可以无阻塞地返回的最小字节数。当你实际调用recv()时,可能会有更多字节到达。

答案 2 :(得分:1)

The short answer is : this cannot be done with MS-Windows WinSock2,
as I can discovered over the last week of trying. 

Glad to have finally found this post, which sheds some light on the issues I've been having, using latest Windows 10 Pro, version 20H2 Build 19042.867 (x86/x86_64) :

On a bound, disconnected UDP socket 'sk' (in Listening / Server mode):

1. Any attempt to use either ioctlsocket(sk, FIONREAD, &n_bytes)
   OR WsaIoctl with a shifted FIONREAD argument, though they succeed,
   and retern 0, after a call to select() returns > with that 
  'sk' FD bit set in the read FD set,
   and the ioctl call returns 0 (success), and n_bytes is > 0, 
   causes the socket sk to be in a state where any
   subsequent call to recv(), recvfrom(), or ReadFile() returns 
   SOCKET_ERROR with a WSAGetLastError() of :
   10045, Operation Not Supported, or ReadFile
   error 87, 'Invalid Parameter'.

Moreover, even worse:

2. Any attempt to use recv or recvfrom with the 'MSG_PEEK' msg_flags 
   parameter returns -1 and WSAGetLastError returns :
   10040 : 'A message sent on a datagram socket was larger than 
    the internal message buffer or some other network limit, 
    or the buffer used to receive a datagram into was smaller 
    than the datagram itself.
       ' .

   Yet for that socket I DID successfully call:
setsockopt(s, SOL_SOCKET, SO_RCVBUF, bufsz = 4096 , sizeof(bufsz) )
   and the UDP packet being received was of only 120 bytes in size.

   In short, with modern windows winsock2 ( winsock2.h / Ws2_32.dll) , 
   there appears to be absolutely no way to use any documented API
   to determine the number of bytes received on a bound UDP socket
   before calling recv() / recvfrom() in MSG_WAITALL blocking mode to
   actually receive the whole packet.

   If you do not call ioctlsocket() or WsaIoctl or 
   recv{,from}(...,MSG_PEEK,...) 
   before entering recv{,from}(...,MSG_WAITALL,...) ,
   then the recv{,from} succeeds.

   I am considering advising clients that they must install and run
   a Linux instance with MS Services for Linux under their windows
   installation , and developing some
   API to communicate with it from Windows, so that reliable 
   asynchronous UDP communication can be achieved - or does anyone 
   know of a good open source replacement for WinSock2 ? 

   I need access to a "C" library TCP+UDP/IP implementation for 
   modern Windows 10  that conforms to its own documentation, 
   unlike WinSock2 -  does anyone know of one ?