boost::asio 只能接收完整的 UDP 数据报吗?

发布于 2024-08-27 00:41:47 字数 569 浏览 5 评论 0原文

我正在使用 boost::asio 构建的 UDP 服务器上工作,我从 教程根据我的需求定制。当我调用 socket.receive_from(boost::asio::buffer(buf), remote, 0, error); 时,它会用数据包中的数据填充我的缓冲区,但是,如果我的理解是正确的,它会删除任何不适合缓冲区的数据。对 receive_from 的后续调用将接收下一个可用的数据报,因此在我看来,甚至在没有通知的情况下都会丢失一些数据。我是否以错误的方式理解这一点?

我尝试一遍又一遍地阅读 boost::asio 文档,但我没有找到关于如何以正确方式执行此操作的线索。我想做的是读取一定量的数据以便我可以处理它;如果读取整个数据报是唯一的方法,我可以做到这一点,但是我怎样才能确保不丢失我收到的数据呢?我应该使用多大的缓冲区大小来确定?有什么方法可以判断我的缓冲区太小并且我正在丢失信息吗?

我必须假设我可能会有意接收大量数据报。

I am working on a UDP server built with boost::asio and I started from the tutorial customizing to my needs. When I call socket.receive_from(boost::asio::buffer(buf), remote, 0, error); it fills my buffer with data from the packet, but, if my understanding is correct, it drops any data that won't fit in the buffer. Subsequent calls to receive_from will receive the next datagram available, so it looks to me like there is some loss of data without even a notice. Am I understanding this the wrong way?

I tried reading over and over the boost::asio documentation, but I didn't manage to find clues as to how I am supposed to do this the right way. What I'd like to do is reading a certain amount of data so that I can process it; if reading an entire datagram is the only way, I can manage that, but then how can I be sure not to lose the data I am receiving? What buffer size should I use to be sure? Is there any way to tell that my buffer is too small and I'm losing information?

I have to assume that I may be receiving huge datagrams by design.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

阳光下慵懒的猫 2024-09-03 00:41:47

这并不是专门针对 boost 的;这就是数据报套接字的工作方式。您必须指定缓冲区大小,如果数据包无法放入缓冲区,那么它将被截断并且无法恢复丢失的信息。

例如,SNMP 协议规定:

该协议的实现不需要接受长度超过 484 个八位字节的消息。但是,建议在可行的情况下实现支持更大的数据报。

简而言之:在设计通信协议时必须考虑到数据报可能会丢失,或者它们可能会被截断超过某个指定的大小。

This is not specific to boost; it's just how datagram sockets work. You have to specify the buffer size, and if the packet doesn't fit into the buffer, then it will be truncated and there is no way to recover the lost information.

For example, the SNMP protocol specifies that:

An implementation of this protocol need not accept messages whose length exceeds 484 octets. However, it is recommended that implementations support larger datagrams whenever feasible.

In short: you have to take it into account when designing your communication protocol that datagrams may be lost, or they may be truncated beyond some specified size.

何以心动 2024-09-03 00:41:47

对于 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.

For IPv4, the datagram size field in the UDP header is 16 bits, giving a maximum size of 65,535 bytes; when you subtract 8 bytes for the header, you end up with a maximum of 65,527 bytes of data. (Note that this would require fragmentation of the enclosing IPv4 datagram regardless of the underlying interface MTU due to the 16-bit IPv4 packet/fragment length field.)

I just use a 64 KiB buffer because it's a nice round number.

You'll want to keep in mind that on the transmitting side you may need to explicitly enable fragmentation if you want to send datagrams larger than will fit in the interface MTU. From my Ubuntu 12.04 UDP(7) manpage:

   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.
酒儿 2024-09-03 00:41:47

getsockopt 与 SO_NREAD 选项结合使用。

来自 Mac OS X 联机帮助页:

SO_NREAD 返回输入缓冲区中可接收的数据量。对于面向数据报的套接字,SO_NREAD 返回第一个数据包的大小 - 这与返回可用数据总量的 ioctl() 命令 FIONREAD 不同。

Use getsockopt with the SO_NREAD option.

From the Mac OS X manpage:

SO_NREAD returns the amount of data in the input buffer that is available to be received. For data-gram oriented sockets, SO_NREAD returns the size of the first packet -- this differs from the ioctl() command FIONREAD that returns the total amount of data available.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文