【发布时间】:2010-09-23 20:11:26
【问题描述】:
我想知道系统队列中下一个 UDP 数据报的大小。
我发现 this question 有类似的疑问,但使用了 boost。最后一个答案(截至 2010 年 9 月 23 日)说了一些关于在 OS X 中使用 getsockopt 和 SO_NREAD 选项的信息,但我在 Windows 中找不到任何相关信息(使用 Winsock)。
Here我发现我可以使用ioctlsocket和FIONREAD来找出整个队列的大小,但是我没有找到关于第一个数据报的任何信息。
所以我的问题是: 有没有办法使用套接字 API 确定队列中下一个 UDP 数据报的大小?(我没有使用 boost)。
我希望我的代码如下所示:
char BigBuffer[ 64 * 1024 ];
void Read( void *Buf, size_t Size ) {
size_t LengthInQueue = WhatTheSizeOfTheNextDatagram();
if( Size < LengthInQueue ) {
recvfrom( Socket, BigBuffer, 64*1024, /*...*/ );
memcpy( Buf, BigBuffer, Size );
}
else {
recvfrom( Socket, Buf, size, /*...*/ );
}
}
为了空间和可读性,我省略了错误检查和一些参数。 我想避免在不需要时复制到中间缓冲区。
【问题讨论】:
-
为什么要这样做?一个 UDP 数据报总是低于 64K。当然,您可以只在 Windows 中提供 64K 缓冲区吗?
-
我试图在读取函数中避免缓冲区复制。
-
在普通的 BSD sockets/POSIX/friends 上,通常使用
recvfrom()和MSG_PEEK标志来完成:即读取 header,计算完整消息中有多少字节,然后终于阅读了整个消息。否则,如果这是禁用 IP 分段的实际 UDP,则 UDP 数据报不能超过 9200 字节,即巨型帧的最大大小(因为 TCP/UDP 的 CRC16 不缩放 9200 字节以上)。 -
请注意,为避免小副本而支付额外系统调用的成本实际上可能不是一个胜利。