連接重置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版本,問題解決
-