SSLSocket 双工关闭失败

问题描述

我收到以下异常:

javax.net.ssl|DEBUG|79|Keep-Alive-Timer|2021-03-29 23:34:12.355 PDT|SSLSocketImpl.java:479|duplex close of SSLSocket<br>
javax.net.ssl|DEBUG|79|Keep-Alive-Timer|2021-03-29 23:34:12.356 PDT|SSLSocketImpl.java:1569|close the underlying socket<br>
javax.net.ssl|DEBUG|79|Keep-Alive-Timer|2021-03-29 23:34:12.356 PDT|SSLSocketImpl.java:1588|close the SSL connection (initiative)<br>
javax.net.ssl|DEBUG|79|Keep-Alive-Timer|2021-03-29 23:34:12.356 PDT|SSLSocketImpl.java:727|close inbound of SSLSocket<br>
javax.net.ssl|WARNING|79|Keep-Alive-Timer|2021-03-29 23:34:12.356 PDT|SSLSocketImpl.java:500|SSLSocket duplex close Failed (
"throwable" : { 
    java.net.socketException: Socket is closed
  at java.base/java.net.socket.shutdownInput(Socket.java:1538)
      at java.base/sun.security.ssl.BaseSSLSocketImpl.shutdownInput(BaseSSLSocketImpl.java:216)
      at java.base/sun.security.ssl.SSLSocketImpl.shutdownInput(SSLSocketImpl.java:742)
      at java.base/sun.security.ssl.SSLSocketImpl.bruteForceCloseInput(SSLSocketImpl.java:692)
      at java.base/sun.security.ssl.SSLSocketImpl.duplexCloSEOutput(SSLSocketImpl.java:553)
      at java.base/sun.security.ssl.SSLSocketImpl.close(SSLSocketImpl.java:485)
      at java.base/sun.net.www.http.HttpClient.closeServer(HttpClient.java:1058)
      at java.base/sun.net.www.http.KeepAliveCache.run(KeepAliveCache.java:183)
      at java.base/java.lang.Thread.run(Thread.java:834)
      at java.base/jdk.internal.misc.InnocuousThread.run(InnocuousThread.java:134)
}

我真的很困惑这个错误是从哪里出现的。

解决方法

正在寻找相同的东西,发现 https://bugs.openjdk.java.net/browse/JDK-8255148 表明此日志记录具有误导性。

,

我在使用 openJDK11 及更高版本时遇到过这种行为,这似乎是由于 Java 11 中为支持 TLSv1.3 新实现了 SSL/TLS 通道。当它被称为同时支持 TLSv1.3 的服务器时,注意到错误,JVM 尝试使用此协议打开一个通道,但没有运气,显然它尚未完全支持。

我通过强制使用 TLSv1.2 找到了一种解决方法(在 OpenJDK11 中很有用),只需在应用程序启动时将以下选项添加到 JVM:-Djdk.tls.client.protocols=TLSv1.2 -Dhttps.protocols=TLSv1.2

请注意,此解决方案并不总是有效,它还取决于您的 Java 代码和使用的库。

第二种方法是降级到 Jdk1.8,默认版本不支持 TLSv1.3,但并不总是可行。

如果您想更详细地研究 TLS 握手,请在启动时添加以下 JVM 参数:-Djavax.net.debug=ssl(有关更多详细信息,请将其设置为 all

编辑

从 2021 年 2 月起,当存储库添加了对 TLSv1.3 (https://updates.jenkins.io) 的支持时,在“附加管理器”中的更新期间,我最初在 openJDK11 上的 Jenkins 中遇到了此错误。在调查该问题的过程中,我发现并尝试使用 jdk11 以下代码 from jenkins issue report:

 public class DownloadWebpageExample {
    public static void main(String[] args) {
        try  {
            URL url = new URL("https://updates.jenkins.io/download/plugins/plugin-util-api/1.2.5/plugin-util-api.hpi");
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            readStream(con.getInputStream());
            // Give output for the command line
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void  readStream(InputStream in)
    {
        char[] buf = new char[1024];
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(in));) {
            while (reader.read(buf,1024) != -1) { }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

通过使用 java -Djavax.net.debug=ssl DownloadWebpageExample 运行它会产生如上所示的错误:

javax.net.ssl|DEBUG|01|main|2021-06-11 12:40:59.499 CEST|SSLSocketImpl.java:636|close inbound of SSLSocket
javax.net.ssl|WARNING|01|main|2021-06-11 12:40:59.501 CEST|SSLSocketImpl.java:494|SSLSocket duplex close failed (
"throwable" : {
  java.net.SocketException: Socket is closed
        at java.base/java.net.Socket.shutdownInput(Socket.java:1521)

使用 java -Djdk.tls.client.protocols=TLSv1.2 -Dhttps.protocols=TLSv1.2 -Djavax.net.debug=ssl DownloadWebpageExample 执行它并不能解决问题。
我用许多 jdk 版本尝试了这段代码,我发现 jdk8 和 openJDK9 不受此行为的影响,但它在 openJDK11- 16.

在 Jenkins 中,我注意到一种不同的行为,通过在 /etc/sysconfig/jenkins 文件中添加如下参数解决了 openJDK11 的问题。对我来说,这是确认它也依赖于源代码实现的错误:

JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true -Djdk.tls.client.protocols=TLSv1.2 -Dhttps.protocols=TLSv1.2"

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...