有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java IOException:在Linux上发送UDP数据包时没有可用的缓冲区空间

我有一个第三方组件,它试图在特定情况下向太多单独的地址发送太多UDP消息。这是软件启动时发生的突发事件,情况是暂时的。实际上,我不确定是消息的数量,还是每个消息都指向一个单独的IP地址

无论如何,更改底层协议或有问题的组件不是一个选项,所以我正在寻找一个解决方法。StackTrace如下所示:

java.io.IOException: No buffer space available
    at java.net.PlainDatagramSocketImpl.send(Native Method)
    at java.net.DatagramSocket.send(DatagramSocket.java:612)

Java版本1.6.0_13和1.6.0_10以及Linux版本Ubuntu9.04和RHEL 4.6(至少)都会出现这个问题

是否有任何Java系统属性或Linux配置调整可能会有所帮助


共 (5) 个答案

  1. # 1 楼答案

    当发送大量消息时,尤其是在Linux中通过千兆以太网发送消息时,内核的库存参数通常不是最优的。您可以通过以下方式增加用于联网的Linux内核缓冲区大小:

    echo 1048576 > /proc/sys/net/core/wmem_max
    echo 1048576 > /proc/sys/net/core/wmem_default
    echo 1048576 > /proc/sys/net/core/rmem_max
    echo 1048576 > /proc/sys/net/core/rmem_default
    

    作为根

    或者使用sysctl

    sysctl -w net.core.rmem_max=8388608 
    

    有很多网络选项

    Linux Network Tuning by IBMMore tuning information

  2. # 2 楼答案

    当我试图在两个本地JVM中使用到数据库的WIFI连接运行coherence cluster时,我遇到了这个错误。。 如果我用以太网运行它,它运行得很好

  3. # 3 楼答案

    我现在也看到了Debian&;瑞尔。在这一点上,我相信我已经将其隔离到NIC和/或NIC驱动程序。你有什么硬件配置?这也显示了这个问题?这似乎只发生在我们最近收购的具有Broadcom Corporation NetXtreme II BCM5708千兆以太网NIC的新Dell PowerEdge服务器上

    我也可以确认,这是在短时间内快速生成出站UDP数据包到许多不同的IP地址。我试图编写一个简单的Java应用程序来复制它(因为我们的应用程序是用snmp4j实现的)

    编辑

    看看我的答案:Java IOException: No buffer space available while sending UDP packets on Linux

  4. # 4 楼答案

    可能有点复杂,但正如我所知,Java使用SPI1模式作为网络子库。这允许您更改用于各种网络操作的实现。如果您使用OpenJDK,那么您可以获得一些关于如何以及如何包装实现的提示。然后,在您的实现中,您可以通过一些睡眠来降低I/O速度

    或者,为了好玩,您可以用修改后的实现覆盖默认的DatagramSocket。它有相同的包名,而且——据我所知——它将优先于默认的JRE类。至少这种方法在一些有缺陷的第三方库中对我有效

    编辑:

    1服务提供者接口是一种在API中分离客户端和服务代码的方法。这种分离允许不同的客户端和不同的提供者实现。通常可以从以Impl结尾的名称中识别出来,就像在堆栈跟踪中一样java.net.PlainDatagramSocketImpl是提供程序实现,其中DatagramSocket是客户端API

    你评论说你不想在整个过程中放慢沟通速度。有几种方法可以避免这种情况,例如测量代码中的时间,并在第一次传入方法调用开始的前1-2分钟内减慢通信速度。然后你就可以不睡觉了

    另一种选择是识别库中行为不端的类,对其进行JAD并修复。然后替换库中的原始类文件

  5. # 5 楼答案

    我终于确定了问题所在。Java IOException具有误导性,因为它“没有可用的缓冲区空间”,但根本问题是本地ARP表已被填充。在Linux上,默认的ARP表查找是1024(文件/proc/sys/net/ipv4/neigh/default/gc_thresh1、/proc/sys/net/ipv4/neigh/default/gc_thresh2、/proc/sys/net/ipv4/neigh/default/gc_thresh3)

    在我的情况下(我假设是你的情况),你的Java代码正在从一个IP地址发送UDP数据包,这个IP地址与你的目标地址在同一个子网中。在这种情况下,Linux机器将执行ARP查找,将IP地址转换为硬件MAC地址。由于您正在向许多不同的IP发送数据包,本地ARP表很快就会填满,达到1024,这时会抛出Java异常

    解决方案很简单,要么通过编辑我前面提到的文件来增加限制,要么将服务器移动到与目标地址不同的子网中,这会导致Linux box不再执行邻居ARP查找(而是由网络上的路由器处理)