如何获取recvmsg的msg_control缓冲区的大小?

时间:2018-02-19 08:17:04

标签: c++ linux recvmmsg

使用recvmsg时,我使用MSG_TRUNCMSG_PEEK,如下所示:

msgLen = recvmsg(fd, &hdr, MSG_PEEK | MSG_TRUNC)

这给了我为下一条消息分配的缓冲区大小

我的问题是如何获取我应该为标题内的msg_control字段分配的缓冲区大小

3 个答案:

答案 0 :(得分:3)

根据the doc,您需要为大小为msg_control的{​​{1}}分配缓冲区。要事先了解尺寸,您可以像调用msg_controllen一样打电话。 MSG_PEEK不会删除消息,MSG_TRUNC将允许返回消息的大小,即使缓冲区太小。

一些解决方案:

  • 调用recvmsg(fd, &hdr, MSG_PEEK | MSG_TRUNC)并根据返回的大小在hdr中初始化缓冲区,并在没有标志的情况下再次调用它。
  • 如果你事先知道你的消息大小,
  • 分配一个足够大的缓冲区,并调用recvmsg。如果发生错误(返回-1),请检查错误代码(如果邮件被截断)(MSG_TRUNC或MSG_CTRUNC)

答案 1 :(得分:1)

我担心你无法从Posix.1g套接字API获得该值。不确定所有实现,但在Linux中不可能。您可能已经注意到,辅助数据缓冲区中没有提供控制流,因此您需要自己实现它,以防您在进程之间发送大量信息。另一方面,对于常见用例,您已经知道在编译时将收到什么(但您可能已经知道了)。如果您需要实现自己的控制流,请在Linux中考虑辅助数据seems to behave,如流套接字。

但是,您可以在/proc/sys/net/core/optmem_max中获取/设置最坏情况方案的缓冲区长度,请参阅cmsg(3)。所以,我猜你可以将它设置为合理的值并声明一个大的缓冲区。

答案 2 :(得分:1)

我不能代表其他平台而不是macOS(其核心基于FreeBSD核心,所以也许它在BSD系统中没有什么不同)而且POSIX标准也没有用,因为它离开了很多协议定义的所有细节,但默认情况下,对于UDP套接字,macOS上recvmsg的行为是根本不提供任何控制数据。无论您在输入上设置msg_control的大小,输出时始终为0。如果您希望接收任何控制数据,首先必须为套接字明确启用它。

E.g。如果你想知道一个数据包的地址,源地址和目的地地址(msg_name只给你一个接收数据包的源地址),那么你必须这样做:

int yes = 1;
setsockopt(soc, IPPROTO_IP, IP_RECVDSTADDR, &yes, sizeof(yes));

现在,您将获得IPv4套接字的目标地址,记录为

  

msghdr结构中的msg_control字段指向缓冲区   包含一个cmsghdr结构,后跟IP地址。 cmsghdr   字段具有以下值:

cmsg_len = sizeof(struct in_addr)
cmsg_level = IPPROTO_IP
cmsg_type = IP_RECVDSTADDR

这意味着您需要在我的系统上提供至少16个字节的存储空间,因为struct cmsghdr在该系统上总是12个字节(4个32位),而IPv4地址是另外4个字节,这个&#39 ; s 16个字节在一起。需要使用CMSG_SPACE宏正确舍入此值,但在我的系统上,宏只确保它是32位的倍数且16字节已经是这样的倍数,因此CMSG_SPACE(16)返回{ {1}}对我而言。

我事先知道我启用了哪些选项以及我将接收哪些控制数据,我可以提前准确计算所需的空间。

对于原始和其他更加模糊的套接字,默认情况下,某些控制数据可能始终包含在输出中,即使未明确启用,但此控制数据的大小始终相等,并且不会从数据包中波动数据包有效负载大小的数据包。因此,一旦你知道正确的大小,你可以依靠它不会改变的事实,至少没有你启用/禁用任何选项。

如果你的控制数据缓冲区太小,总是在输出中设置16标志(即使你没有在输入上设置任何标志),那么你需要增加控制数据缓冲区大小并重试(使用下一个数据包或使用相同的数据包,如果您使用MSG_CTRUNC作为输入标志),直到您曾经能够在没有获得MSG_PEEK标志的情况下进行该调用在输出上。最后看看MSG_CTRUNC字段的内容。在输入时,它是可用的缓冲区空间量,但在输出时它包含实际使用的确切缓冲区空间量。这是接收该套接字所有未来数据包的控制数据所需的确切缓冲区大小,除非您更改将导致更多/更少控制数据被发送的选项,然后您只需再次检测该大小,就像再次检测该大小一样。之前。

有关更完整的示例,您还可以查看:
https://stackoverflow.com/a/49308499/15809