Java - “没有可用的缓冲区空间”套接字错误原因?

时间:2010-12-14 06:43:42

标签: java sockets tcp buffer serversocket

我正在用Java编写网络程序。我使用ServerSocket和Socket对象使用TCP发送和接收消息。如果我运行的时间很短,我的程序运行正常,但如果我运行它的时间较长,我会收到以下错误:

java.net.SocketException: No buffer space available (maximum connections reached?): connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(Unknown Source)
at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)

我认为可能是因为我没有关闭所有套接字但是我已经改变了我的代码:当我想要一个新的套接字并添加了一个finalize方法来关闭它时,我创建了一个类。我还有一个关闭ServerSocket的finalize方法,所以我不知道问题是什么。

此外,在我收到错误后,如果我立即再次运行该程序,它会比以前更快地遇到问题。然后,如果我等待一段时间并运行它,它会回到原来的时间。

我真的无法解决这个问题,而且我一直试图弄清楚这个问题。有谁知道问题是什么?

提前致谢!

更新

所以我已经弄清楚了错误的来源,这真的很奇怪。我有以下代码导致问题:

try {
        sock = new Socket(InetAddress.getByName(ipaddr), port);
        sock.close();

        // os = sock.getOutputStream();
        // byte[] arr = s.getBytes();
        // os.write(arr);
        // os.close();

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            sock.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

如您所见,代码应该打开一个套接字并写入它。然而,即使所有功能代码都被如上所述注释掉,所以套接字刚刚打开然后立即关闭,我仍然得到“无缓冲区空间”错误。

我真的无法理解为什么会这样。该程序是多线程的,每个线程使用上述方法定期创建对象并调用它。删除创建和关闭套接字的行时,我不再收到错误,但是当它们在那里时,即使套接字打开然后立即关闭,我也会收到错误。

有没有人知道为什么会发生这种情况?

非常感谢。

2 个答案:

答案 0 :(得分:5)

  
    

我想创建一个新的套接字时创建了一个类,并添加了 finalize 方法来关闭它。我还有一个 finalize 方法来关闭ServerSocket,所以我不知道是什么问题。

  

Bzzt。停止。校验。终结器在运行时是不确定的(除了在对象不再可达之后的某个时间,尽管Java应用程序终止时可能不会!) - 请参阅Destroying and Finalizing。确保您使用的是明确的合同,例如Closable并通过它来调用它(不要等待GC出现!)。

这个问题最能说明是“泄漏”了外部资源 - 因为GC主要关心的是内存和内存压力,如果压力很小和/或GC没有攻击性,那么很容易耗尽外部资源资源首先是因为终结器未运行(尚未)。一般来说,终结者是一个安全网(并不总是有效),但不能替代其他形式的外部资源管理。

从上面的链接:

  
    

Java不保证何时会发生垃圾收集或收集对象的顺序。因此, Java无法保证何时(甚至是否)将调用终结器,将以什么顺序调用终结器,或者什么线程将执行终结器。

  

快乐的编码。

修改:请参阅此相关问题:Why would you ever implement finalize()?。我喜欢史蒂夫杰索普的第二个回应。

答案 1 :(得分:2)

请勿使用finalize关闭资源。它不会可靠地工作。

(有可能资源对象不会很快完成,你将耗尽资源。你无法控制终结器何时运行,并且它们可能永远不会运行。)

你应该做的是这样的事情:

    Resource resource = // allocate resource
    try {
        // Use the resource ...
    } 
    catch (SomeException ...) {
        // Deal with errors from using the resource
    } 
    finally {
        try {
            resource.close()}
        }
        catch (SomeException ...) {
            // Deal with errors from closing the resource
        }
    }