14

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

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

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

4

4 回答 4

37

你要找的是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确定何时准备好读取数据,O_NONBLOCK如果您想确保永远不会阻塞 recv,则套接字标志非常方便.

于 2012-10-20T03:00:30.937 回答
3

在 Windows 上,您可以使用ioctlsocket()带有FIONREAD标志的函数来询问套接字有多少字节可用,而无需自己读取/查看实际字节。recv()返回的值是可以在没有阻塞的情况下返回的最小字节数。当您实际调用 时recv(),可能已经到达了更多字节。

于 2012-10-20T03:39:39.827 回答
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 ?
于 2021-03-15T15:27:58.627 回答
0

使用时要小心FIONREAD!using 的问题ioctl(fd, FIONREAD, &available)是它总是会返回在某些系统上的套接字缓冲区中可供读取的字节总数。

这对于 STREAM 套接字 (TCP) 没有问题,但对于 DATAGRAM 套接字 (UDP) 会产生误导。对于数据报套接字,读取请求被限制为缓冲区中第一个数据报的大小,当读取的数据小于第一个数据报的大小时,该数据报的所有未读字节仍然被丢弃。所以理想情况下,您只想知道缓冲区中下一个数据报的大小。

例如,在 macOS/iOS上,记录FIONREAD始终返回总金额(参见关于 的评论SO_NREAD)。要仅获取下一个数据报的大小(以及流套接字的总大小),您可以使用以下代码:

int available;
socklen_t optlen = sizeof(readable);
int err = getsockopt(soc, SOL_SOCKET, SO_NREAD, &available, &optlen);

在 LinuxFIONREAD上记录为仅返回UDP 套接字的下一个数据报的大小。

在 Windowsioctlsocket(socket, FIONREAD, &available)上记录为始终给出总大小:

如果在 s 参数中传递的套接字是面向消息的(例如,类型 SOCK_DGRAM),FIONREAD 将返回报告可读取的字节总数,而不是在套接字上排队的第一个数据报(消息)的大小。

来源:https ://docs.microsoft.com/en-us/windows/win32/api/ws2spi/nc-ws2spi-lpwspioctl

我不知道如何仅在 Windows 上获取第一个数据报的大小。

于 2021-12-09T11:32:33.523 回答