我们说我有一个发送者应用程序和一个通过UDP进行通信的接收器应用程序。
首先,在发件人应用程序中,我通过两个单独的调用发送一些数据。首先,我发送这15个字节:
[MYHEADER]hello
...然后,在此之后,我再发送15个字节:
[MYHEADER]world
现在,在接收器应用程序中,我正在使用UDP套接字侦听同一端口,该套接字绑定到同一地址。让我们说自从我上次检查接收器套接字以来,这两条消息都已到达(并且顺序相同)。
这里有一些伪代码,显示我如何每帧轮询套接字以获取传入数据:
uint32 PendingSize;
while (Socket->HasPendingData(PendingSize))
{
uint32 BytesRead;
uint8 MessageData[kMaxMessageSize];
if (Socket->Recv(MessageData, kMaxMessageSize, BytesRead))
{
// Do stuff here
// Will BytesRead be equal to PendingSize?
}
}
HasPendingData
用ioctlsocket
包含对FIONREAD
的调用,返回数据是否在接收缓冲区中等待,并用等待的字节数填充PendingSize
。 Recv
调用recv
将该数据读入我可以读取的缓冲区。如果它返回true,那么我会回复我收到的数据。
这是我的问题。以下哪种情况准确地反映了在这种情况下会发生什么?
选项A.
HasPendingData
返回true并显示15字节的待处理大小。 Recv
向我发送了消息[MYHEADER]hello
。HasPendingData
返回true并显示15字节的待处理大小。 Recv
向我发送了消息[MYHEADER]world
。HasPendingData
返回false。选项B。
HasPendingData
返回true并显示30字节的待处理大小。 Recv
向我发送了消息[MYHEADER]hello[MYHEADER]world
。HasPendingData
返回false。任何见解都表示赞赏。谢谢!
答案 0 :(得分:2)
UDP数据报是独立且独立的。
send()
和sendto()
每次都会发送一个新的数据报。
recv()
和recvfrom()
读取整个数据报。如果您的缓冲区太小而无法接收给定的数据报,则会出现WSAEMSGSIZE
错误,如果您未指定MSG_PEEK
标志,该数据报将会丢失。
FIONREAD
告诉您套接字接收缓冲区中的原始字节总数,而不是数据报的数量,或者这些数据报的大小。这在documentation:
FIONREAD
用于确定可从套接字读取的网络输入缓冲区中待处理的数据量。 argp参数指向ioctlsocket存储结果的unsigned long值。 FIONREAD返回一次调用recv函数可以读取的数据量,这可能与套接字上排队的数据总量不同。 如果s是面向消息的(例如,键入SOCK_DGRAM),FIONREAD仍会返回网络缓冲区中待处理数据的数量,但是,在对recv函数的单次调用中实际可以读取的数量仅限于在send或sendto函数调用中写入的数据大小。
如果您需要检查下一个数据报的大小,请使用recv()
标记来呼叫recvfrom()
或MSG_PEEK
。一旦确定了数据报的实际大小,就可以在没有标志的情况下读取它,以便从套接字缓冲区中删除它。否则,只需分配一个足够大的缓冲区以容纳您将收到的最大数据报,或者甚至只分配65535,这是UDP支持的最大大小。
因此,要回答您的问题,您的示例中实际发生的是选项A ,但第一个HasPendingData
将报告30个待处理字节而不是15个。