【问题标题】:Why 'java.net.SocketException: Socket closed' after 'java.net.ConnectException: Connection refused'?为什么在“java.net.ConnectException:连接被拒绝”之后出现“java.net.SocketException:套接字已关闭”?
【发布时间】:2022-01-10 08:29:56
【问题描述】:

我正在尝试连接到一个远程主机,一遍又一遍地等待它出现。但是,在出现 Connection Refused 异常(因为服务器尚未运行)后,它会不断抛出 Socket closed 异常。为什么套接字会被关闭?套接字应该简单地处于与失败的 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

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

【问题讨论】:

    标签: java sockets connection-refused


    【解决方案1】:

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

    这是 Java 11 中的代码(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 */
                }
            }
        }
    }
    

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


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

    讨论Socket 这样做是否正确是无关紧要的。它只是......而且这种情况不太可能改变。唯一可能改变的是他们可能Socket javadocs 中记录此行为。

    【讨论】:

    • 是的,API 就是这样。谢谢,想确保我没有做错什么。每次你解释它时,我都花了 5 分钟来向上扩展 while 循环以创建一个新的套接字。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-10
    • 1970-01-01
    • 2015-05-18
    • 2018-06-10
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多