何时需要修改套接字的接收缓冲区大小?

4

我时常会看到一些网络相关的代码(包括遗留代码)和其他地方使用 setsockopt 函数并设置 SO_RCVBUF 选项来修改 socket 的接收缓冲区大小。在我的 Windows 10 系统中,socket 的默认缓冲区大小似乎为 64KB。我现在正在处理的遗留代码(编写于 10 多年前)将每个 socket 的接收缓冲区大小设置为 256KB。

以下是与此相关的一些问题:

  1. 如果 socket 被连续监视和读取(例如使用 select),是否有任何理由修改接收缓冲区大小?
  2. 如果没有,那么十多年前有什么动机呢?
  3. 是否有任何示例、用例或应用程序需要修改 socket 的接收缓冲区大小(甚至发送缓冲区大小)?

这回答了你的问题吗?SO_SNDBUF和SO_RECVBUF是什么。也就是说,它是__应用程序特定__的 - 如果在读取之前缓冲区已满,则发送方将被告知减慢TCP/IP或丢弃UDP数据包。因此,这取决于应用程序的处理方式。 - Richard Critten
1
可能有一部分是正确的,但并不完全准确。我知道缓冲区是什么以及它们的工作原理。我的问题更多地涉及实践中何时使用它们。 - arghol
我们需要更多的上下文才能回答这个问题。数据包是否会突发到达?它们是如何处理的,是否可以被中断等等?这可能对于一个类似于SO的问答网站来说太过复杂了。 - Richard Critten
在我的具体示例中,网络流量负载较低至中等,并且传入的数据在其自己的线程中持续处理。虽然我的问题旨在更加通用,但也许很难对此做出一般性的说法。 - arghol
2个回答

3
通常情况下,接收缓冲区大小被修改为更大是因为代码作者尝试减少套接字接收缓冲区变满并因此导致操作系统不得不丢弃一些传入的数据包的情况的概率。在基于TCP的应用程序中,这种情况会导致流暂时停顿,直到重新发送丢失的数据包成功;在基于UDP的应用程序中,这种情况会导致传入的UDP数据包被静默丢弃。
是否需要这样做取决于两个因素:数据有多快填满套接字的接收缓冲区,以及应用程序通过调用recv()有多快能够清空套接字的接收缓冲区。如果应用程序能够可靠地比接收到的数据更快地排空缓冲区,则默认缓冲区大小就可以了;另一方面,如果您发现它不能总是做到这一点,则较大的接收缓冲区大小可能有助于它更优雅地处理突发的传入数据。
如果套接字在不断监视和读取(例如使用select),是否有任何理由修改接收缓冲区大小呢?如果传入数据速率很高(例如每秒兆字节甚至只是偶尔以那种速率的数据突发),或者如果线程在select()/recv()调用之间做一些可能使其忙碌相当长时间的事情,比如线程需要写入磁盘,则在某些情况下磁盘写入调用可能需要几百毫秒,这可能允许套接字的接收缓冲区在此期间填满。
对于非常高带宽的应用程序,即使非常短暂的暂停(例如由于线程在几个量子时间内被CPU踢出,以便另一个线程可以运行一两个量子时间),也足以允许缓冲区填满。这很大程度上取决于应用程序的使用情况,当然还取决于CPU硬件速度与网络速度的关系。
至于何时开始干预接收缓冲区大小:除非您注意到应用程序正在丢失足够多的传入数据包以明显限制应用程序的网络性能,否则不要这样做。没有必要分配比所需更多的RAM。

1
在TCP中,数据速率由TCP窗口进行管理。端点不需要丢弃任何数据。但是,在传输过程中,路由器可能会丢弃数据。 - doron
@doron 数据不会丢失,但是数据包可能会丢失;这将导致TCP数据传输比本来可能要慢。 - Jeremy Friesner
数据仅会被IP层丢弃,而且只有在数据包无法路由时才会发生。 - doron

3
对于TCP协议,RECVBUF缓冲区是内核可以容纳的最大未读字节数。在TCP中,窗口大小反映了发送者可以安全发送的未确认字节数的最大值。发送者将收到一个包含新窗口的ACK,该窗口取决于RECVBUF中的可用空间。
当RECVBUF已满时,发送者将停止发送数据。这种机制意味着发送者无法发送超过接收应用程序能够接收的数据量。
小的RECVBUF在低延迟网络上运行良好,但在高带宽高延迟网络上,ACKS可能需要太长时间才能到达发送者,并且由于发送者已经用完了窗口,因此发送者将无法利用全部带宽。
增加RECVBUF大小会增加窗口大小,这意味着发送者在等待ACK时可以发送更多数据,然后这将允许发送者利用整个带宽。这确实意味着响应速度较慢。
缩小RECVBUF意味着发送者更具响应性,并且意识到接收者没有消耗数据,可以更快地退出。
SENDBUF也适用相同的逻辑。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接