连接重置Connection reset

异常java.net.SocketException: Connection reset

详细信息

java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:210)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
    at sun.security.ssl.InputRecord.read(InputRecord.java:503)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:373)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
    at com.senthink.www.oc.http.HttpRequester.execute(HttpRequester.java:170)

场景回溯

  1. 首次请求 首次向电信物联网平台API发送Https请求时报错
  2. 未得到响应
  3. 只有Soctet异常:Connection Reset

出现原因

Connection Reset——其中一端主动断开连接

Connection Reset是在建立TCP连接之后,其中一方的TCP标志位使用了Reset标志主动重置了连接

客户端Or服务器端

而我这里既然是客户端报的错误信息,那势必是服务器主动断开了连接

为什么它要断开连接

服务器主动断开连接的原因:

  • 服务器异常
  • 服务器和客户端长短连接不匹配
  • Https连接,服务器和客户端的TLS版本不一致

原因排查

  • 服务器异常 电信作为三大运营商,它的服务器出现异常的可能性不大
  • 长短连接不匹配 如果是长短连接不匹配,那么也是第一次响应之后短连接方断开连接,而我跟本没有收到响应,因此可以排除长短连接不一致的情况
  • Https连接,TLS版本不一致

用排除法分析出:此时连接重置的原因是TLS版本不一致

解决方法

  • 查服务器端支持的TLS版本,然后切换请求客户端的TLS版本

    可以查指定域名TLS版本的网站

  • 试出来服务器端支持的TLS版本

    1. 打开Http客户端的配置(我用的是HttpClient,它的TLS配置在SSL连接工厂中的String数组参数)

      public CloseableHttpClient closeableHttpClient() throws Exception {
          // Trust own CA and all self-signed certs
          String userDir = System.getProperty("user.dir");
          SSLContext sslcontext = SSLContexts.custom()
              .loadTrustMaterial(
              new File(userDir + ocSetting.getCertPathCA()),
              ocSetting.getCertPasswordCA().toCharArray(),
              new TrustSelfSignedStrategy())
              .loadKeyMaterial(
              new File(userDir + ocSetting.getCertPathOutGoing()),
              ocSetting.getCertPasswordOutGoing().toCharArray(),
              ocSetting.getCertPasswordOutGoing().toCharArray())
              .build();
          // Allow TLSv1 protocol only
          //这里的问题,这里配置只允许TLSv1版本
          SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
              sslcontext,
              new String[] { "TLSv1"},
              //new String[] {"TLSv1","TLSv1.1","TLSv1.2",疯狂往里加}
              null,
              SSLConnectionSocketFactory.getDefaultHostnameVerifier());
      
          return HttpClients.custom().setSSLSocketFactory(sslsf).build();
      }
    2. 以此切换TLS版本,直到不再出现Connection Reset

      TLS版本有哪些?,这个在sun.security.ssl.ProtocolVersion中可以看到

      static final ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
      static final ProtocolVersion SSL20Hello = new ProtocolVersion(2, "SSLv2Hello");
      static final ProtocolVersion SSL30 = new ProtocolVersion(768, "SSLv3");
      static final ProtocolVersion TLS10 = new ProtocolVersion(769, "TLSv1");
      static final ProtocolVersion TLS11 = new ProtocolVersion(770, "TLSv1.1");
      static final ProtocolVersion TLS12 = new ProtocolVersion(771, "TLSv1.2");
    3. 换上服务器支持的TLS版本,问题解决
技术不分领域,思想一脉相承,欢迎访问橙味菌的博客
本文由博客一文多发平台 OpenWrite 发布!

程围军
4 声望0 粉丝