在UDP套接字上即时更改SOL_SOCKET,SO_RCVBUF的可预期行为是什么?

问题描述

如果在Linux系统上即时调整UDP服务器套接字的输入缓冲区大小,应该发生什么?

setsockopt(sock,SOL_SOCKET,SO_RCVBUF,...)

我对这些问题特别感兴趣:

  • 如果我缩小到缓冲区中当前的大小以下,这会简单地删除最旧/最新的吗?数据报是否正确,或者是否刷新其中的所有内容,或更糟的是它会破坏数据,例如截断数据报?
  • 缩小缓冲区会节省内存还是会阻止内存被系统重用?
  • 该行为是否可以预测或有时会随机出现?

解决方法

首先,“缓冲区”一词可能令人困惑:内核实际上并未将包保存在固定大小的缓冲区中,而是保存在称为“积压”的队列中(请参阅include/net/sock.h:400)。通过SO_RCVBUFSO_SNDBUF设置的大小仅限制了积压的最大大小。

如果我缩小到缓冲区中的当前值以下,这会简单地删除最旧/最新的内容吗?

否,保留已收到的内容。没有数据报被丢弃。当您执行setsockopt(SO_RECVBUF)时,唯一发生的事情就是the value of the sk_rcvbuf field of the socket is changed。没有其他动作。

只有在接收到更多数据包时才能看到其真正的效果:接收到的所有后续数据报将被立即丢弃,并将继续丢弃,直到队列缩小到设置的大小以下(即用户空间接收到足够的数据报)为止。

缩小缓冲区会节省内存还是会阻止内存被系统重用?

如前所述,由于“缓冲区”实际上不是缓冲区,并且没有固定大小,因此更改SO_RECVBUF不会立即更改任何内容。

有两种情况:

  1. 如果待办订单大小小于或等于指定的大小:新的最大大小将受到限制,因此将来会在处节省内存可能丢失数据包的成本。
  2. 如果待办事项大小大于指定的大小:当用户空间接收到缓冲的数据包时,内存最终将被释放,并且不会再次超出设置值。将来会再次节省内存。

该行为是否可以预测或有时会随机出现?

看看内核代码,我会说以我上面描述的方式是100%可预测的。但是,我不确定这在哪里记录。我想说的是,如果您考虑将“缓冲区”作为队列发送(实际上就是队列),那是很直观的。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...