javax.net.ssl.SSLException:读取错误:ssl = 0x9524b800:系统调用期间发生I / O错误,由对等方重置连接

我们的客户在过去的几个星期里开始看到这些“SSLException错误 – 由同行重置连接”的100个数据,我不明白为什么

  1. 我们使用okhttp进行Retrofit,没有特别的configuration

    public class OkHttpClientProvider implements IOkHttpClientProvider { OkHttpClient okHttpClient; public OkHttpClientProvider() { this.okHttpClient = createClient(); } public OkHttpClient getOkHttpClient() { return this.okHttpClient; } private OkHttpClient createClient() { return new OkHttpClient(); } } 

上面的客户端提供程序是一个单身人士。 RestAdapter是使用这个注入的客户端(我们使用匕首)构build的 –

 RestAdapter.Builder restAdapterBuilder = new RestAdapter.Builder() .setConverter(converter) .setEndpoint(networkRequestDetails.getServerUrl()) .setClient(new OkClient(okHttpClientProvider.getOkHttpClient())) .setErrorHandler(new NetworkSynchronousErrorHandler(eventBus)) ); 

基于堆栈溢出解决scheme,我发现了 –

  1. 在服务器上的保持活动持续时间是180秒,OkHttp默认为300秒

  2. 服务器在其标题中返回“Connection:close”,但客户端请求发送“Connection:keepAlive”

  3. 服务器支持TLS 1.0 / 1.1 / 1.2并使用Open SSL

  4. 我们的服务器最近在另一个地理位置移动到另一个托pipe服务提供商,所以我不知道这些DNS是否失败

  5. 我们已经尝试调整keepAlive之类的东西,在服务器上重新configurationOpenSSL,但由于某种原因Android客户端不断收到此错误

  6. 当你尝试使用应用程序发布或拉动刷新(它甚至没有进入networking或在发生这种意外连接已经断开之前有延迟)时,立即发生,没有任何延迟。 但多次尝试“修复”,我们取得了成功。 它稍后再发生

  7. 我们已经使我们在服务器上的DNS条目无效,看看这是什么原因造成的,但没有帮助

  8. 它主要发生在LTE上,但我也在Wifi上看到它

我不想禁用保持活着,因为大多数现代客户不这样做。 此外,我们使用OkHttp 2.4,这是后冰淇淋三明治设备的问题,所以我希望它应该照顾这些底层的networking问题。 iOS客户端也获得这些例外,但接近100倍(iOS客户端使用AFNetworking 2.0)。 我在努力寻找新的东西尝试在这一点上,任何帮助/想法?

更新 – 通过okhttp添加完整的堆栈跟踪

  retrofit.RetrofitError: Read error: ssl=0x9dd07200: I/O error during system call, Connection reset by peer at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:390) at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240) at java.lang.reflect.Proxy.invoke(Proxy.java:397) at $Proxy15.getAccessTokenUsingResourceOwnerPasswordCredentials(Unknown Source) at com.company.droid.repository.network.NetworkRepository.getAccessTokenUsingResourceOwnerPasswordCredentials(NetworkRepository.java:76) at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.java:88) at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.java:23) at android.os.AsyncTask$2.call(AsyncTask.java:292) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:818) Caused by: javax.net.ssl.SSLException: Read error: ssl=0x9dd07200: I/O error during system call, Connection reset by peer at com.android.org.conscrypt.NativeCrypto.SSL_read(Native Method) at com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:699) at okio.Okio$2.read(Okio.java:137) at okio.AsyncTimeout$2.read(AsyncTimeout.java:211) at okio.RealBufferedSource.indexOf(RealBufferedSource.java:306) at okio.RealBufferedSource.indexOf(RealBufferedSource.java:300) at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:196) at com.squareup.okhttp.internal.http.HttpConnection.readResponse(HttpConnection.java:191) at com.squareup.okhttp.internal.http.HttpTransport.readResponseHeaders(HttpTransport.java:80) at com.squareup.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:917) at com.squareup.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:793) at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:439) at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:384) at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497) at com.squareup.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:105) at com.squareup.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:25) at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:73) at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:38) at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:321)            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)            at java.lang.reflect.Proxy.invoke(Proxy.java:397)            at $Proxy15.getAccessTokenUsingResourceOwnerPasswordCredentials(Unknown Source)            at com.company.droid.repository.network.NetworkRepository.getAccessTokenUsingResourceOwnerPasswordCredentials(NetworkRepository.java:76)            at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.java:88)            at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.java:23)            at android.os.AsyncTask$2.call(AsyncTask.java:292)            at java.util.concurrent.FutureTask.run(FutureTask.java:237)            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)            at java.lang.Thread.run(Thread.java:818) ]} 

最近我在处理一些遗留代码时遇到了这个问题。 谷歌search后,我发现这个问题无处不在,但没有任何具体的解决办法。 我处理了exception信息的各个部分,并在下面分析。

分析:

  1. SSLException :在JDK( openJDK/oracleJDK/AndroidSDK )的javax.net.ssl包中实现的SSL(安全套接字层)
  2. Read error ssl=# I/O error during system call :从安全套接字读取时发生错误。 它发生在使用本地系统库/驱动程序。 请注意,所有的平台solaris,Windows等都有自己的套接字库供SSL使用。 Windows使用WINSOCK库。
  3. Connection reset by peer :此消息由系统库(Solaris报告ECONNRESET ,Windows报告WSAECONNRESET )报告,由于现有连接被远程主机强制closures,数据传输中使用的套接字不再可用。 需要在主机和客户端之间创build一个新的安全path

原因:

了解这个问题,我试着找出连接重置的原因,我想出了下面的原因:

  • 远程主机上的对等应用突然停止,主机重新启动,主机或远程networking接口被禁用,或远程主机使用硬closures。
  • 如果由于保活活动在一个或多个操作正在进行时检测到故障而导致连接中断,则也可能导致此错误。 正在进行的操作Network dropped connection on reset(On Windows( WSAENETRESET ))失败,并且随后的操作失败,同时Connection reset by peer(On Windows( WSAECONNRESET ))
  • 如果目标服务器受到防火墙的保护(在大多数情况下都是如此),则与端口相关的生存时间(TTL)或超时在给定的超时时间强制closures空闲连接。 这是我们感兴趣的事情

parsing度:

  1. 服务器端的事件,如突然停止服务,重新启动,禁用networking接口不能以任何方式处理。
  2. 在服务器端,为具有更高生存时间(TTL)或超时值(如3600秒)的给定端口configuration防火墙。
  3. 客户端可以“尝试”使networking保持活动状态,以避免或减lessConnection reset by peerConnection reset by peer
  4. 正常情况下,networkingstream量会使连接保持活跃状态​​,并不经常出现问题/exception。 强大的Wifi有最小的机会Connection reset by peer
  5. 对于分组数据传送间歇且取决于移动networking可用性的移动networking2G,3G和4G ,其可能不会重置服务器侧的TTL计时器并导致Connection reset by peer方进行的Connection reset by peer

这里是build议在各种论坛上设置的术语来解决这个问题

  • ConnectionTimeout:仅在连接超时时使用。 如果主机花费时间连接更高的值,则会使客户端等待连接。
  • SoTimeout :套接字超时 – 它表示接收数据包的最大时间,以将连接视为活动。如果在给定时间内没有收到数据,则认为连接被中止/中断。
  • Linger :当数据排队发送时,什么时候套接字不应该closures,套接字上调用close套接字函数。
  • TcpNoDelay :你是否想要禁用保存和累积TCP数据包的缓冲区,并在达到阈值时发送它们? 将其设置为true将跳过TCP缓冲,以便立即发送每个请求。 networking速度减慢可能是由于更小更频繁的数据包传输造成的networkingstream量增加。

所以上述参数都没有帮助保持networking活跃,因此无效。

我发现了一个可能有助于解决这个function的问题

 setKeepAlive(true) setSoKeepalive(HttpParams params, enableKeepalive="true") 

我怎么解决我的问题?

  • 设置HttpConnectionParams.setSoKeepAlive(params, true)
  • 捕获SSLException并检查Connection reset by peer的exception消息
  • 如果发现exception,请存储下载/读取进度并创build一个新的连接。
  • 如果可能恢复下载/读取其他重新启动下载

我希望细节帮助。 快乐编码

如果使用Nginx并得到类似的问题,那么这可能会有所帮助:

在此sslTesturl上扫描您的域名,并查看您的设备版本是否允许连接。

如果由于TLS支持,较低版本的设备(如<Android 4.4.2等)无法连接,请尝试将其添加到Nginxconfiguration文件中,

 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 

我们今天早上有同样的问题,并得到它解决…希望这有助于…

IIS 8上的SSL

  1. 一切工作正常昨天昨晚我们的SSL更新在IIS网站上。
  2. 检查站点绑定到SSL注意到,IIS8有一个新的checkbox要求服务器名称指示 ,它没有被选中,所以先启用它。
  3. 这引发了这个问题。
  4. 回到IIS,禁用checkbox….问题解决!!!!

希望这可以帮助!!!

此错误消息的另一个可能的原因是如果HTTP方法被服务器或负载平衡器阻止。

阻止未使用的HTTP方法似乎是标准的安全措施 。 我们遇到了这个问题,因为HEAD被负载平衡器阻塞(但奇怪的是,并非所有的负载平衡服务器,导致它只有一些时间失败)。 我能够testing,请求本身工作正常,暂时改变它使用GET方法。

iOS上的错误代码是:错误请求应用程序代码:错误域= NSURLErrorDomain代码= -1005“networking连接丢失。