连接重置Connection reset异常

详细信息

java.net.SocketException: Connection reset
	at java.net.SocketInputStream.read(SocketInputStream.java:168)
	at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
	at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:789)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1096)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:623)
	at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
	at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
	at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
	at org.apache.commons.httpclient.methods.StringRequestEntity.writeRequest(StringRequestEntity.java:146)
	at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:499)
	at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114)
	at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
	at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
	at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
	at com.venustech.pm.flow.propchange.comm.http.HttpClientUtil.doPostPayload(HttpClientUtil.java:91)
	at com.venustech.pm.flow.propchange.comm.http.HttpClientUtil$1.run(HttpClientUtil.java:431)
	at java.lang.Thread.run(Thread.java:619)

场景回溯

  1. 首次请求 首次向其他系统API发送Https请求时报错
  2. 未得到响应
  3. 只有Soctet异常:Connection Reset

出现原因

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

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

客户端Or服务器端

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

为什么它要断开连接

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

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

原因排查

  • 服务器异常    运维给到结果,可以telnet通,但是curl不通,说明端口可以连接上但是握手失败,已经升级证书解决,curl可以连接,但是reset问题还未解决
  • 长短连接不匹配   如果是长短连接不匹配,那么也是第一次响应之后短连接方断开连接,而我跟本没有收到响应,因此可以排除长短连接不一致的情况
  • Https连接,TLS版本不一致(本次主要原因是线上老系统用的是jdk1.6, 默认支持tls1.0,调用的系统是jdk1.8,默认支持tls1.1)

解决方法

  • 查服务器端支持的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版本,问题解决

本次公司解决方案

把nginx 支持的tls版本降低了,支持了tls1.0,虽然场景不同,但是原因相同

 补充一些用法,客户端和服务器统一使用TCP短连接

既不用改nginx配置,也不用改tomcat配置,只需在使用HttpClient时使用http1.0协议并增加http请求的header信息(Connection: Close),源码如下:

httpGet.setProtocolVersion(HttpVersion.HTTP_1_0);

httpGet.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值