【问题标题】:UDP datagram sockets - What are the possible causes of failure of send() for "No buffer space available"UDP 数据报套接字 - “没有可用的缓冲区空间”的 send() 失败的可能原因是什么
【发布时间】:2021-03-23 10:56:52
【问题描述】:

我正在一个廉价的 Digital Ocean 液滴上测试我的代码(2GB 内存,但我也尝试添加 4GB 交换空间,但没有任何改变)。

我的程序的一部分有许多 UDP 客户端 DGRAM 套接字打开到各种本地端口(从/到 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。这些都不会改变任何东西。

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

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

可能的原因是什么?

【问题讨论】:

    标签: linux sockets networking udp kernel


    【解决方案1】:

    错误No buffer space available 并不意味着套接字缓冲区已满。这意味着 linux 内核无法为套接字缓冲区分配内存。任何套接字缓冲区都没有内存,因此当这种情况发生时,在释放一些内存之前,不可能通过任何套接字发送任何数据。增加wmem_max 和rmem_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。

    如果内存实际上被套接字缓冲区消耗,那么添加交换几乎没有帮助,因为 AFAIK 缓冲区不能被换出。

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

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

    【讨论】:

    • 因此,换句话说,各个套接字缓冲区未已满(SO_SNDBUF),但它们全部占用了太多,以至于内核无法找到更多(非交换)内存用于他们?至于增加 wmem_max/rmem_max 和 SO_SNDBUF 有人提到内存在需要时才实际使用:stackoverflow.com/questions/64523733/…你同意吗?
    • 我在检查/proc/net/sockstat 和free -h 时设法重现,平均而言,180 个套接字从不超过 80 页(因为它们中的大多数只是在等待使用),但非然而,交换内存达到了问题发生的临界点。谢谢!现在我知道套接字本身没有问题,它们只是系统内存不足时最先失败的事情。
    • 是的,缓冲区的内存是在需要时分配的——通常是在接收到数据或应用程序调用send 时。如果套接字缓冲区已满(数据等待发送或数据等待读取),则内核丢弃一些数据但不报告错误。 UDP 是允许的。但正如您所写 - 问题在于整体内存消耗。套接字缓冲区的 80 页并不是很多。可能还有其他的记忆吞噬者。
    猜你喜欢
    • 2011-05-25
    • 1970-01-01
    • 2018-03-11
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-05
    • 1970-01-01
    相关资源
    最近更新 更多