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

tre*_*ker 0 java sockets buffer tcp 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)
Run Code Online (Sandbox Code Playgroud)

我认为这可能是因为我没有关闭所有套接字但是我已经改变了我的代码:当我想要一个新的套接字并添加了一个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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

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

有没有人知道为什么会这样?

非常感谢.

小智 5

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

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

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

从上面的链接:

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

快乐的编码.

编辑:请参阅此相关问题:为什么要实现finalize()?.我喜欢Steve Jessop的第二个回应.