连接重置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)
场景回溯
- 首次请求 首次向电信物联网平台API发送Https请求时报错
- 未得到响应
- 只有Soctet异常:Connection Reset
出现原因
Connection Reset——其中一端主动断开连接
Connection Reset是在建立TCP连接之后,其中一方的TCP标志位使用了Reset标志主动重置了连接
客户端Or服务器端
而我这里既然是客户端报的错误信息,那势必是服务器主动断开了连接
为什么它要断开连接
服务器主动断开连接的原因:
- 服务器异常
- 服务器和客户端长短连接不匹配
- Https连接,服务器和客户端的TLS版本不一致
原因排查
-
服务器异常电信作为三大运营商,它的服务器出现异常的可能性不大 -
长短连接不匹配如果是长短连接不匹配,那么也是第一次响应之后短连接方断开连接,而我跟本没有收到响应,因此可以排除长短连接不一致的情况 - Https连接,TLS版本不一致
用排除法分析出:此时连接重置的原因是TLS版本不一致
解决方法
- 查服务器端支持的TLS版本,然后切换请求客户端的TLS版本
-
试出来服务器端支持的TLS版本
-
打开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(); }
-
以此切换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");
- 换上服务器支持的TLS版本,问题解决
-
技术不分领域,思想一脉相承,欢迎访问橙味菌的博客
本文由博客一文多发平台 OpenWrite 发布!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。