【问题标题】:What is the predictable behavior of changing SOL_SOCKET, SO_RCVBUF on the fly on a UDP socket?在 UDP 套接字上即时更改 SOL_SOCKET、SO_RCVBUF 的可预测行为是什么?
【发布时间】:2020-10-25 12:34:23
【问题描述】:

如果我们在 Linux 系统上动态调整 UDP 服务器套接字的输入缓冲区大小,会发生什么?

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

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

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

【问题讨论】:

    标签: sockets networking linux-kernel udp setsockopt


    【解决方案1】:

    首先:“缓冲区”一词可能会让人混淆:内核实际上并没有将数据包保存在固定大小的缓冲区中,而是保存在称为“积压”的队列中(参见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% 可预测。但是,我不完全确定这可能会记录在哪里。如果您将发送和接收“缓冲区”视为队列(它们实际上是),我会说这有点直观。

    【讨论】:

      猜你喜欢
      • 2014-09-05
      • 2013-04-15
      • 1970-01-01
      • 2012-04-21
      • 1970-01-01
      • 2014-02-26
      • 1970-01-01
      • 2020-11-21
      • 1970-01-01
      相关资源
      最近更新 更多