【发布时间】:2020-03-13 18:00:24
【问题描述】:
说明
我正忙着用 Go 编写一个高频 UDP 服务器。我估计两种方式至少每秒 1000 个数据包。
但是,随着我通过 UDP 套接字发送的数据大小增加,我最终遇到了以下错误:read udp 127.0.0.1:1541->127.0.0.1:9737: wsarecv: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.
我最终只是增加了我正在读取和写入的缓冲区的大小,如下所示:
buffer := make([]byte, 64 * 1024 * 1024) // used to just be 1024
l, err := s.socketSim.Read(buffer)
这工作正常,我停止收到错误...但是我可以跨 net 包内的两个函数:
s.socketSim.SetWriteBuffer(64 * 1024 * 1024)
s.socketSim.SetReadBuffer(64 * 1024 * 1024)
我了解到这两个作用于operating system's transmit buffer
问题
我是否关心设置操作系统缓冲区大小,为什么?应用程序缓冲区的大小如何影响操作系统缓冲区的大小?它们是否应该始终相同,它们应该/可以变得多大?
【问题讨论】:
-
您确定要首先编写大型 UDP 数据包吗?该规范将 UDP 帧大小限制为 65535,因此您实际上不能发送大于 65507(或 IPv6 IIRC 上的 65527)的有效负载。即便如此,这也需要在整个链路上支持巨型帧以防止分段(在大多数情况下为 44 个数据包,丢包的可能性是丢弃整个数据报的 44 倍)
-
普遍接受的 UDP 数据报有效负载的实际限制是 534 字节。除此之外的任何事情都会导致 IP 碎片化,因此会增加丢包的风险。
-
我宁愿避免丢包,也不愿使用更大的负载。所以我会根据规格保持尺寸。仍然有点困惑为什么我可以选择更改它......那么在哪种情况下大型 UDP 数据包是理想的?
-
@FanusduToit,当您控制网络并知道 MTU 时,大型 UDP 数据包工作得很好,因此它们不会分段。读写缓冲区不是数据包大小,它们只是用于读写的缓冲区,通常不需要设置。无论您将缓冲区设置为什么,您都不能在单个数据包中发送超过 65535 个字节,因为长度字段只有 16 位。
-
例如,如果您正在构建一个在本地使用以太网巨型帧 (~9k) 的网络,并且您的 UDP 连接是纯本地的,那么您就知道可以发送 8KiB 的数据块因为他们只会进入一个巨型帧。设置这样的代码通常是明智的,以便您可以处理更常规的限制,但是,因为承诺的本地网络通常在销售人员接触它之后,不得不也可以在 WAN 空间玩 :-)