sockets - 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 缓冲区更大,特别是在数据是突发的和处理密集型的情况下。如果您的数据以一致的速率进入并且您仍在丢弃数据包,那么您处理它们的速度不够快。
推荐阅读
- javascript - 如何在 azure function app v2 中将表存储设置为输出?
- javascript - React 中更新后的状态类型更改
- c - 如何获取stm32的IP?
- javascript - NgModel在第一次onclick angular 5时没有更新
- tesseract - 使用 stdout 作为输出时,在 tesseract 中禁用“Page x”的输出
- javascript - 在 TS 中为长类定义动态装饰器而不重新定义所有方法的方法
- python - PYODBC 连接字符串 - 调用信息时使用转换器
- django-filter - 如何使用graphene-django通过GraphQL中的id列表过滤查询?
- java - 按通用元素对对象的数组列表进行排序
- javascript - 匹配字符串中的单词,无论中间有什么