Java SocketException: 没有可用的缓冲区

5

我的Java代码使用了多个线程,每个线程运行一个ServerSocket并进入accept状态。这些线程使用Java Socket进行通信。当我使用121个线程时,一切都正常工作,但是如果我使用256个线程运行相同的代码,则会出现以下错误:

java.net.SocketException: No buffer space available (maximum connections reached?): listen failed
    at java.net.PlainSocketImpl.socketListen(Native Method)
    at java.net.PlainSocketImpl.listen(Unknown Source)
    at java.net.ServerSocket.bind(Unknown Source)
    at java.net.ServerSocket.<init>(Unknown Source)
    at java.net.ServerSocket.<init>(Unknown Source)

我使用的是Windows XP SP3操作系统,遇到了类似这篇文章(这里)所述的问题,但是没有人提供解决方案。我已经安装了Windows补丁以删除TCP连接限制,但是并未解决我的问题。


你的系统是否能快速处理传入的连接? - Thorbjørn Ravn Andersen
4个回答

7

这条信息表示您的连接可能已用尽。您是否检查过?您可以使用以下命令行检查打开的套接字:

netstat -n

请确保在两端都关闭所有套接字(在finally块中)。记住,在接收到连接后,监听套接字仍然保持打开状态。不要过快地打开和关闭套接字(我会说它们不能立即重用,这可能与您的问题有关)。

为了获得更好的与套接字相关的性能,您可以使用java.nio API,但它比java.net复杂得多。


谢谢,我通过更改ServerSocket调用解决了问题。我的错误是将backlog值设置得太高了。我不需要服务器监听超过5-6个连接。 我用以下代码替换了原来的代码: ServerSocket sock=new ServerSocket(port,10); 现在一切都正常工作! - tulkas85

4
我认为这篇文章可能会有你需要的答案。留下悬空套接字会导致您达到最大值(可能由Windows补丁无法修复的其他设置决定(例如JVM限制)?)
顺便说一句,如果您使用那么多线程运行,最好使用java.nio而不是Java的简单Socket和ServerSocket类。 这个网站是一个非常好的教程,介绍了如何使用java.nio,也是我学习它的方式(以及查看Sun/Oracle的Java NIO API),之前我只使用简单的Socket和ServerSocket编程。
具体来说,有助于您的事业的是使用Selector,这将允许您以与C++ select()调用处理套接字相同的方式复用套接字I/O。这意味着在您的套接字代码的核心中,您可以减少处理套接字I/O的大量线程的影响,并且只有一个线程直接与套接字交互。

第一个链接已经失效。 - xxfelixxx

2

我通过更改ServerSocket调用方法解决了问题。我的错误在于将backlog值设置得太高。我不需要服务器监听超过5-6个连接。我将以下代码:ServerSocket sock=new ServerSocket(port,500); 替换为 ServerSocket sock=new ServerSocket(port,10); 现在一切正常工作!


1

不知道你具体在做什么,这只是一个猜想,但我会提供以下建议以防其他人遇到类似问题。当尝试打开太多的OUTGOING连接时,我曾看到过这个错误。通过减小缓冲区大小,您已经限制了连接线程打开的连接数(当达到缓冲区限制时,它们将被拒绝)。如果您仍然得到足够的吞吐量,那么这是一个很好的解决方案。然而,另一个解决方案是增加可用的输出连接数量,这可能会修复您的问题并提供更好的吞吐量。

要实现这一点,您可以添加/修改MaxUserPort的注册表项。使用regedit,找到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters,然后添加/修改键:MaxUserPort类型为DWORD和一个高值,如65534(十进制)

关于MaxuserPort,这里有一篇usoft tech article


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