为什么 'java.net.SocketException: Socket closed' 在 'java.net.ConnectException: Connection refused' 之后?

Why 'java.net.SocketException: Socket closed' after 'java.net.ConnectException: Connection refused'?

我正在尝试连接到远程主机,一遍又一遍地等待它出现。但是,在出现一次拒绝连接异常后(因为服务器还没有运行),它会连续抛出套接字关闭异常。为什么套接字会被关闭?套接字应该简单地处于与失败的 connect() 调用之前相同的状态,不是吗?

                while(!tcpSock.isConnected()) {
                    try {
                        tcpSock.connect(destination);
                    } catch (SocketException e) {
                        System.err.println(e.toString());
                    }
                }

结果

Setting TCP client mode connecting to remote host localhost/127.0.0.1 port 4500
java.net.ConnectException: Connection refused: connect
java.net.SocketException: Socket closed
java.net.SocketException: Socket closed
java.net.SocketException: Socket closed
java.net.SocketException: Socket closed

期望的行为是

Setting TCP client mode connecting to remote host localhost/127.0.0.1 port 4500
java.net.ConnectException: Connection refused: connect
java.net.ConnectException: Connection refused: connect
java.net.ConnectException: Connection refused: connect
java.net.ConnectException: Connection refused: connect
Established connection to: localhost port 4500

(一旦我完成调试,我将注释掉异常的打印。)

查看 OpenJDK 源代码...当 connect(...) 调用失败时,SocketImpl 代码在 Socket 上调用 close()

这是Java11(java.net.AbstractPlainSocketImpl)中的代码:

protected void connect(String host, int port)
    throws UnknownHostException, IOException
{
    boolean connected = false;
    try {
        InetAddress address = InetAddress.getByName(host);
        this.port = port;
        this.address = address;

        connectToAddress(address, port, timeout);
        connected = true;
    } finally {
        if (!connected) {
            try {
                close();  // <<---- HERE
            } catch (IOException ioe) {
                /* Do nothing. If connect threw an exception then
                   it will be passed up the call stack */
            }
        }
    }
}

SocketImpl 对象的 close() 调用导致 Socket 被标记为已关闭。


简而言之,Java Socket 对象不支持在连接尝试失败后重试。如果您想重试,您的代码需要创建一个新的 Socket 对象。

关于 Socket 这样的行为是否 正确 的讨论是离题的。确实如此……而且这种情况极不可能改变。唯一可能改变的是他们 可能 Socket javadocs 中记录此行为。