在将 UDP 数据报读入缓冲区之前找出其大小?

问题描述 投票:0回答:1

我想接收任意大小的整个 UDP 数据报并将字节放入缓冲区。但是,在分配缓冲区之前,我需要找出数据报的大小。不幸的是,我在任何地方都找不到这样做的例子,StackOverflow 上的任何答案似乎都没有完全解决这个问题。

我能想到的最好的办法是:

sockaddr_in senderAddress;
memset(&senderAddress, 0, sizeof(senderAddress));
socklen_t senderAddressLen = sizeof(senderAddress);
ssize_t datagramLength = recvfrom(udpSocket, nullptr, 0, MSG_PEEK, reinterpret_cast<sockaddr*>(&senderAddress), &senderAddressLen);

不幸的是,这总是返回零,即使

recvfrom()
具有实际提供的缓冲区将返回非零字节。

我想到,也许

recvfrom()
的长度参数可能是问题所在,但将其更改为更大的值只会导致
recvfrom()
返回错误,特别是“错误地址”。这可能是因为传递的数据指针为空。

还有其他可能的方法可以做到这一点,但它们在不同系统中返回的内容似乎不一致。考虑这里最后一条评论

还有一个问题有人问过这个问题(接收整个UDP数据报,无论大小?),但解释非常简短,即使我包括

MSG_TRUNC
,它对我也不起作用。

另一个问题(know udp packet size with poll select or epoll)提到使用

MSG_PEEK
,但它并没有完全解决问题,而且似乎假设你想偷看数据。

我其实不想看数据。我只想找出长度,然后分配一个缓冲区,然后将数据读入其中。有办法做到这一点吗?

谢谢!

注意:虽然我计划在 Linux 上运行它,但我是在 Mac 上进行原型设计。

MSG_TRUNC
似乎已经定义了,但似乎没有做任何事情。

c++ udp posix datagram recvfrom
1个回答
0
投票

在将 UDP 数据报读入缓冲区之前找出其大小?

POSIX 没有定义任何方法来做到这一点。您使用

ioctl()
展示并介绍了潜在的技术,但是 POSIX 没有定义除 STREAMS 文件之外的任何 ioctl(不要与 C 流或面向流的套接字协议混淆)。您还提到了一种涉及将
MSG_TRUNC
标志传递给
recv()
recvfrom()
的技术,但是

  1. MSG_TRUNC
    没有被 POSIX 记录,并且
  2. 即使它可以访问未截断的大小(就像在 Linux 上一样),您也应该期望它与(可能被截断的)消息一起返回,而不是在将消息读入缓冲区之前返回。 但是如果
      recv()
    • /
      recvfrom()
      完全接受它,您应该能够将
      MSG_TRUNC
      MSG_PEEK
      结合起来以避免消耗消息,这样您就可以进行第二次往返以将整个消息接收到足够大的缓冲区。这适用于 Linux,但不一定适用于其他 POSIX 平台。
      
      
  3. 总体而言,实际上很少需要您所请求的功能,因为一般来说,UDP 应用程序在它们使用的数据报大小上具有内置的、特定于应用程序的上限。所以不

接收任意大小的整个UDP数据报

,这并不是什么东西。

最坏的情况下,UDP 协议能够表示的最大有效负载大小略小于 64 KiB,因此如果您不想施加任何其他限制,那么您至少可以依赖它。

在分配缓冲区之前,我需要找出数据报的大小

如果“分配”是指“动态”分配,那么您可能最好使用足够大的自动数组来代替。其中“足够大”意味着足以容纳应用程序支持的最大数据报,该数据报不能超过 64 KiB,但可能会限制为更小的数据报。在某些情况下,您可能想要创建动态分配的副本,但即使如此,额外的分配和副本可能仍然优于额外的系统调用。

注意:虽然我计划在 Linux 上运行它,但我是在 Mac 上进行原型设计。 MSG_TRUNC

似乎已经定义了,但似乎没有做任何事情。

如果您想要同时在 Mac 和 Linux 上运行的东西,那么您可能确实希望将自己限制在 POSIX 指定的功能上。这很大程度上使您处于“[没有]定义[d]方式来执行此操作”类别。如上所述,最好的选择是将数据报接收到足够大的缓冲区中,以容纳远程对等方可以发送的任何有效消息。

© www.soinside.com 2019 - 2024. All rights reserved.