UDP套接字是否将接收到的数据描述为不同的消息,或者是否一次性读取尽可能多的数据?

时间:2014-10-03 18:50:39

标签: c++ networking udp winsock

我们说我有一个发送者应用程序和一个通过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?
    }
}

HasPendingDataioctlsocket包含对FIONREAD的调用,返回数据是否在接收缓冲区中等待,并用等待的字节数填充PendingSizeRecv调用recv将该数据读入我可以读取的缓冲区。如果它返回true,那么我会回复我收到的数据。

这是我的问题。以下哪种情况准确地反映了在这种情况下会发生什么?

选项A.

  1. HasPendingData返回true并显示15字节的待处理大小。 Recv向我发送了消息[MYHEADER]hello
  2. HasPendingData返回true并显示15字节的待处理大小。 Recv向我发送了消息[MYHEADER]world
  3. HasPendingData返回false。
  4. 选项B。

    1. HasPendingData返回true并显示30字节的待处理大小。 Recv向我发送了消息[MYHEADER]hello[MYHEADER]world
    2. HasPendingData返回false。
    3. 任何见解都表示赞赏。谢谢!

1 个答案:

答案 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个。