首页 > 解决方案 > UDP SetWriteBuffer 和 SetReadBuffer 如何处理操作系统的缓冲区?

问题描述

描述

我正忙着用 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

问题

我是否关心设置操作系统缓冲区大小,为什么?应用程序缓冲区的大小如何影响操作系统缓冲区的大小?它们是否应该始终相同,它们应该/可以变得多大?

标签: socketsgoudpbuffer

解决方案


首先,您不仅有设备上每个接口的 MTU 大小以及发送/接收的任何目的地,而且两者之间的每个设备也有一个 MTU 大小。出于这个原因,正如其他人所提到的,您可能希望使用 MTU 普遍接受的内容,因为您可能无法控制数据路由中的每个设备。在 UDP 的情况下,MTU 实际上只是表示数据报在分片之前可以有多大。

其次,您几乎肯定希望您的 SND/RCV 缓冲区大于 MTU。这些是内核缓冲区,当您还没有准备好接收数据时,它们会保留数据。更大的 UDP RCV 缓冲区意味着内核会在将它们放入深渊之前为您缓冲更多的数据包。也许您对每个数据包都有一些重要的工作要做。根据比特率,您可能需要更大或更小的内核缓冲区。

最后,您使用的是 UDP。无法保证您会按顺序或完全收到数据包。您和对等方之间的任何路由器都可能出于任何原因决定丢弃数据包。由于您使用的是 UDP,因此您应该为丢弃和乱序的数据包做好准备。您可能还需要某种重传机制,这会使事情变得更加复杂。

或者,如果丢弃的数据包不可接受,您可能会考虑使用 TCP,因为您知道时间是不确定的。

如果您使用的是 linux,则可以在 /proc/sys/net 中查看当前缓冲区大小。通常内核会加倍你的要求。

此外,您可以通过观察 /proc/net/udp 中的数据包丢失来调整缓冲区大小。如果您看到下降,您可能希望使您的 rcv 缓冲区更大,特别是在数据是突发的和处理密集型的情况下。如果您的数据以一致的速率进入并且您仍在丢弃数据包,那么您处理它们的速度不够快。


推荐阅读