私たちのクライアントはここ数週間でこれらの「SSLExceptionエラー-ピアによる接続のリセット」を何百も見始めていますが、その理由はわかりません。
OkhttpでRetrofitを使用しており、特別な構成はありません
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は、この注入されたクライアントを使用して構築されます(短剣を使用します)-
RestAdapter.Builder restAdapterBuilder = new RestAdapter.Builder()
.setConverter(converter)
.setEndpoint(networkRequestDetails.getServerUrl())
.setClient(new OkClient(okHttpClientProvider.getOkHttpClient()))
.setErrorHandler(new NetworkSynchronousErrorHandler(eventBus))
);
私が見つけたスタックオーバーフローソリューションに基づいて-
サーバーのキープアライブ期間は180秒で、OkHttpのデフォルトは300秒です
サーバーはヘッダーで「Connection:close」を返しますが、クライアント要求は「Connection:keepAlive」を送信します
サーバーはTLS 1.0/1.1/1.2をサポートし、Open SSLを使用します
サーバーは最近、別の地域の別のホスティングプロバイダーに移動したため、これらがDNS障害であるかどうかはわかりません
KeepAliveなどの調整を試み、サーバーでOpenSSLを再構成しましたが、何らかの理由でAndroidクライアントがこのエラーを取得し続けます
アプリを使用して何かを投稿したり、更新するためにプルしようとすると、遅延なくすぐに発生します(接続が既に切断されていることを示すこの例外が発生する前に、ネットワークにアクセスしたり、遅延することさえありません)。しかし、何回かそれを「修正する」ことを試みて、私たちは成功します。後でまた起こる
サーバー上のDNSエントリを無効にして、これが原因かどうかを確認しましたが、それは役に立たなかった
ほとんどLTEで発生しますが、Wifiでも見ました
キープアライブを無効にしたくないのは、最近のクライアントのほとんどがそうしないからです。また、OkHttp 2.4を使用しており、これはポストアイスクリームサンドイッチデバイスの問題であるため、これらの根本的なネットワークの問題に対処することを望んでいます。 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)
]}
最近、いくつかのレガシーコードの作業中に問題に直面しました。グーグルで調べたところ、問題はどこにでもあるが、具体的な解決策がないことがわかりました。例外メッセージのさまざまな部分に取り組み、以下で分析しました。
分析:
SSLException
:JDKのjavax.net.ssl
パッケージに実装されているSSL(Secure Socket Layer)で例外が発生しました(openJDK/oracleJDK/AndroidSDK
)Read error ssl=# I/O error during system call
:セキュアソケットからの読み取り中にエラーが発生しました。ネイティブシステムライブラリ/ドライバーを使用中に発生しました。すべてのプラットフォームsolaris、Windowsなどには、SSLによって使用される独自のソケットライブラリがあることに注意してください。 WindowsはWINSOCKライブラリを使用します。Connection reset by peer
:このメッセージはシステムライブラリによって報告されます(SolarisはECONNRESET
を報告し、WindowsはWSAECONNRESET
を報告します。既存の接続が強制的に使用されたため、データ転送で使用されたソケットは使用できなくなりましたリモートホストによって閉じられます。ホストとクライアントの間に新しい安全なパスを作成する必要があります理由:
問題を理解し、接続がリセットされた理由を見つけようとしましたが、以下の理由を思いつきました。
Network dropped connection on reset(On Windows(WSAENETRESET))
で失敗し、後続の操作はConnection reset by peer(On Windows(WSAECONNRESET))
で失敗します。解像度:
Connection reset by peer
を回避または削減するためにネットワークをアクティブに保ちます。Connection reset by peer
の可能性が最も低い。Connection reset by peer
になります。問題を解決するためにさまざまなフォーラムで設定することが提案されている用語は次のとおりです。
ConnectionTimeout:
接続の確立時にのみ使用されます。ホストが接続に時間がかかる場合、この値が高いほど、クライアントは接続を待機します。SoTimeout
:ソケットタイムアウト-接続をアクティブと見なすためにデータパケットを受信する最大時間を示します。指定された時間内にデータが受信されない場合、接続は停止または中断したと見なされます。Linger
:送信するデータがキューに入れられ、ソケットでソケットのクローズ関数が呼び出されたときに、ソケットをクローズしない時間まで。TcpNoDelay
:TCPパケットを保持および蓄積するバッファーを無効にし、しきい値に達したら送信しますか?これをtrueに設定すると、TCPバッファリングがスキップされ、すべてのリクエストがすぐに送信されます。ネットワークの速度低下は、パケット送信がより小さく頻繁に行われることによるネットワークトラフィックの増加によって引き起こされる場合があります。したがって、上記のパラメーターはどれも、ネットワークの存続を維持するのに役立ち、したがって無効になります。
この機能である問題の解決に役立つ可能性のある設定を見つけました
setKeepAlive(true)
setSoKeepalive(HttpParams params, enableKeepalive="true")
問題の解決方法
HttpConnectionParams.setSoKeepAlive(params, true)
を設定しますSSLException
をキャッチし、Connection reset by peer
の例外メッセージを確認します詳細がお役に立てば幸いです。ハッピーコーディング...
Nginx
を使用して同様の問題が発生する場合、これが役立つ場合があります。
この sslTesturl でドメインをスキャンし、デバイスバージョンで接続が許可されているかどうかを確認します。
下位バージョンのデバイス(<Android 4.4.2など)がTLSサポートのために接続できない場合は、これをNginx構成ファイルに追加してみてください。
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
今朝からこの同じ問題が発生しましたが、解決しました...これが役立つことを願っています...
IIS 8のSSL
お役に立てれば!!!
Androidは、Android N(APIレベル24)およびAndroid 5.1(APIレベル22)以下を除き、デフォルトでSSL実装をサポートします
サーバー側でSSLを実装した後、APIレベル22未満のデバイスでAPI呼び出しを行うとエラーが発生しました。これは、OkHttpClientクライアントオブジェクトの作成中に発生し、connectionSpecs()メソッドOkHttpClient.Builderクラスを追加することで修正されました。
受信したエラーは
応答の失敗:javax.net.ssl.SSLException:SSLハンドシェイクの中止:ssl = 0xb8882c00:システムコール中のI/Oエラー、ピアによる接続のリセット
だから私は次のようなチェックを追加してこれを修正しました
if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.Lollipop_MR1) {
// Do something for below api level 22
List<ConnectionSpec> specsList = getSpecsBelowLollipopMR1(okb);
if (specsList != null) {
okb.connectionSpecs(specsList);
}
}
Android Nの場合(APIレベル24);次のようなHTTP呼び出しを行っているときにエラーが発生しました
HTTP失敗:javax.net.ssl.SSLHandshakeException:ハンドシェイクに失敗しました
これは、特にAndroid 7のチェックを追加することで修正されます。
if (Android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.N){
// Do something for naugat ; 7
okb.connectionSpecs(Collections.singletonList(getSpec()));
}
したがって、最終的なOkHttpClientオブジェクトは次のようになります。
OkHttpClient client
HttpLoggingInterceptor httpLoggingInterceptor2 = new
HttpLoggingInterceptor();
httpLoggingInterceptor2.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder okb = new OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor2)
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request request2 = request.newBuilder().addHeader(AUTH_KEYWORD, AUTH_TYPE_JW + " " + password).build();
return chain.proceed(request2);
}
}).connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS);
if (Android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.N){
// Do something for naugat ; 7
okb.connectionSpecs(Collections.singletonList(getSpec()));
}
if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.Lollipop_MR1) {
List<ConnectionSpec> specsList = getSpecsBelowLollipopMR1(okb);
if (specsList != null) {
okb.connectionSpecs(specsList);
}
}
//init client
client = okb.build();
getSpecsBelowLollipopMR1関数は、
private List<ConnectionSpec> getSpecsBelowLollipopMR1(OkHttpClient.Builder okb) {
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, null, null);
okb.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()));
ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build();
List<ConnectionSpec> specs = new ArrayList<>();
specs.add(cs);
specs.add(ConnectionSpec.COMPATIBLE_TLS);
return specs;
} catch (Exception exc) {
Timber.e("OkHttpTLSCompat Error while setting TLS 1.2"+ exc);
return null;
}
}
Tls12SocketFactoryクラスは以下のリンクにあります(gotevによるコメント):
https://github.com/square/okhttp/issues/2372
以下のリンクを追加するサポートが必要な場合は、詳細に役立ちます。
https://developer.Android.com/training/articles/security-ssl
このエラーメッセージの別の考えられる原因は、HTTPメソッドがサーバーまたはロードバランサーによってブロックされている場合です。
未使用のHTTPメソッドをブロックするのは 標準セキュリティ慣行 のようです。 HEADがロードバランサーによってブロックされていたため、これに遭遇しました(しかし、奇妙なことに、負荷分散されたサーバーのすべてではなく、一部の場合にのみ失敗しました)。 GETメソッドを使用するように一時的に変更することで、リクエスト自体が正常に機能することをテストできました。
IOSのエラーコードは次のとおりでした:アプリコードの要求エラー:エラードメイン= NSURLErrorDomainコード= -1005「ネットワーク接続が失われました。」