UDP 数据报套接字 - "No buffer space available" 的 send() 失败的可能原因是什么

UDP datagram sockets - What are the possible causes of failure of send() for "No buffer space available"

我正在一个便宜的 Digital Ocean droplet 上测试我的代码(2GB 内存,但我也尝试添加 4GB 的交换空间,但它没有改变任何东西)。

我程序的一部分有许多 UDP 客户端 DGRAM 套接字打开到各种本地端口 (from/to 127.0.0.1)。

有时,如果没有发送大量数据,send() 调用会失败并显示 No buffer space available(错误 105)。

然后我的程序尝试使用所有其他可用的套接字(到其他本地端口),但它们都同时失败。

我已将 /proc/sys/net/core/wmem_max(和 /proc/sys/net/core/rmem_max)设置为 16MB,并且每个插槽都已将 setsockopt SOL_SOCKET, SO_SNDBUF 设置为 8MB。 None 这些改变了一切。

send() 怎么会因 No buffer space available 而失败?这不是应该只在我们 send() 太快时发生吗?但这是本地的,我不会发送很多数据。

最让我困惑的是,当进程重试任何另一个套接字时,它会得到同样的错误。套接字缓冲区不应该是完全独立的吗?

可能的原因是什么?

错误No buffer space available并不意味着套接字缓冲区已满。这意味着 linux 内核无法为套接字缓冲区分配内存。没有用于任何套接字缓冲区的内存,因此当这种情况发生时,在释放一些内存之前不可能通过任何套接字发送任何数据。增加 wmem_maxrmem_max 可能会使问题变得更糟,因为它们可能会增加每个套接字的内存消耗。您可以检查总体内存消耗以及为 udp 套接字缓冲区分配了多少内存:

$ cat /proc/net/sockstat
sockets: used 315
TCP: inuse 8 orphan 0 tw 0 alloc 13 mem 1
UDP: inuse 3853 mem 240812
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0

本例中的 UDP 套接字每 4KB 使用 240812 页,即 ~940MB。有 3853 个打开的套接字

$ free -h
              total        used        free      shared  buff/cache   available
Mem:           1.9G        1.8G         75M        1.2M         66M         28M
Swap:            0B          0B          0B

本示例中的系统具有 2 GB 物理内存和非常低的可用内存。 send 函数很可能因错误 No buffer space available.

而失败

如果内存实际上被套接字缓冲区消耗,那么添加交换几乎没有帮助,因为据我所知缓冲区无法换出。

您可以试试内存更大的虚拟机。它可能有助于或至少推迟问题。

您还可以审核应用程序并检查套接字的使用情况。 UDP 套接字缓冲区的高内存消耗可能是由应用程序中的错误或错误的设计引起的。例如,如果应用程序侦听 UDP 套接字并且有数据但应用程序未读取任何内容,则内核不会释放内存,直到进程终止或直到应用程序调用 recv。很多没有调用就打开的套接字 recv 可能会耗尽内存。