我正在使用boost :: asio构建的UDP服务器,我从tutorial开始定制到我的需求。当我调用socket.receive_from(boost::asio::buffer(buf), remote, 0, error);
时,它会使用数据包中的数据填充我的缓冲区,但是,如果我的理解是正确的,它会丢弃任何不适合缓冲区的数据。对receive_from的后续调用将接收下一个可用的数据报,因此在我看来,即使没有通知,也会有一些数据丢失。我理解这是错误的方法吗?
我试着一遍又一遍地阅读boost :: asio文档,但我没有设法找到关于我应该以正确的方式做这件事的线索。我想做的是读取一定数量的数据,以便我可以处理它;如果读取整个数据报是唯一的方法,我可以管理它,但是我怎么能确保不丢失我收到的数据?我应该使用什么缓冲区大小来确定?有没有办法告诉我我的缓冲区太小而且我丢失了信息?
我必须假设我可能会按设计收到大量的数据报。
答案 0 :(得分:9)
这不是特定的提升;这就是数据报套接字的工作原理。您必须指定缓冲区大小,如果数据包不适合缓冲区,则它将被截断,并且无法恢复丢失的信息。
例如,SNMP协议指定:
此协议的实现不需要接受长度超过484个八位字节的消息。但是,建议实现在可行的情况下支持更大的数据报。
简而言之:在设计通信协议时,您必须考虑到数据报可能会丢失,或者它们可能被截断超出某些指定的大小。
答案 1 :(得分:3)
对于IPv4,UDP报头中的数据报大小字段为16位,最大大小为65,535字节;当您为标头减去8个字节时,最终会得到最多65,527个字节的数据。 (请注意,由于16位IPv4数据包/片段长度字段,无论底层接口MTU如何,都需要对封闭的IPv4数据报进行分段。)
我只使用64 KiB缓冲区,因为它是一个很好的整数。
您需要记住,在发送方面,如果要发送大于适合接口MTU的数据报,则可能需要明确启用分段。从我的Ubuntu 12.04 UDP(7)联机帮助页:
By default, Linux UDP does path MTU (Maximum Transmission Unit) discov‐
ery. This means the kernel will keep track of the MTU to a specific
target IP address and return EMSGSIZE when a UDP packet write exceeds
it. When this happens, the application should decrease the packet
size. Path MTU discovery can be also turned off using the IP_MTU_DIS‐
COVER socket option or the /proc/sys/net/ipv4/ip_no_pmtu_disc file; see
ip(7) for details. When turned off, UDP will fragment outgoing UDP
packets that exceed the interface MTU. However, disabling it is not
recommended for performance and reliability reasons.
答案 2 :(得分:1)
将getsockopt
与SO_NREAD选项一起使用。
从Mac OS X联机帮助页:
SO_NREAD返回可用于接收的输入缓冲区中的数据量。对于面向数据的套接字,SO_NREAD返回第一个数据包的大小 - 这与返回可用数据总量的ioctl()命令FIONREAD不同。