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

问题

我甚至想设置操作系统缓冲区大小吗?为什么?应用程序缓冲区大小如何影响操作系统缓冲区的大小?它们应该一直保持不变吗?它们应该/可以变得多大?

首先,您不仅为设备上的每个接口以及从哪个目的地发送/接收信息都有一个MTU大小,而且还为介于两者之间的每个设备提供了一个MTU大小。因此,正如其他人所提到的,您可能希望使用MTU通常接受的方法,因为您可能无法控制数据路由中的每个设备。在UDP的情况下,MTU实际上只是指数据报在分段之前可以有多大。

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

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

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

如果您在linux上,您可以在/proc/sys/net中看到当前的缓冲区大小。通常内核会使您的要求翻倍。

此外,您还可以通过在/proc/net/udp中观察数据包丢失来调整缓冲区大小。如果您看到下降,您可能希望增大rcv缓冲区,尤其是在数据突发且处理密集的情况下。如果数据以一致的速率传入,并且仍在丢弃数据包,则说明处理速度不够快。

最新更新