web-dev-qa-db-ja.com

javax.net.ssl.SSLException:読み取りエラー:ssl = 0x9524b800:システムコール中のI / Oエラー、ピアによる接続のリセット

私たちのクライアントはここ数週間でこれらの「SSLExceptionエラー-ピアによる接続のリセット」を何百も見始めていますが、その理由はわかりません。

  1. 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))
                                        );

私が見つけたスタックオーバーフローソリューションに基づいて-

  1. サーバーのキープアライブ期間は180秒で、OkHttpのデフォルトは300秒です

  2. サーバーはヘッダーで「Connection:close」を返しますが、クライアント要求は「Connection:keepAlive」を送信します

  3. サーバーはTLS 1.0/1.1/1.2をサポートし、Open SSLを使用します

  4. サーバーは最近、別の地域の別のホスティングプロバイダーに移動したため、これらがDNS障害であるかどうかはわかりません

  5. KeepAliveなどの調整を試み、サーバーでOpenSSLを再構成しましたが、何らかの理由でAndroidクライアントがこのエラーを取得し続けます

  6. アプリを使用して何かを投稿したり、更新するためにプルしようとすると、遅延なくすぐに発生します(接続が既に切断されていることを示すこの例外が発生する前に、ネットワークにアクセスしたり、遅延することさえありません)。しかし、何回かそれを「修正する」ことを試みて、私たちは成功します。後でまた起こる

  7. サーバー上のDNSエントリを無効にして、これが原因かどうかを確認しましたが、それは役に立たなかった

  8. ほとんど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)
      ]}
50
Rickster

最近、いくつかのレガシーコードの作業中に問題に直面しました。グーグルで調べたところ、問題はどこにでもあるが、具体的な解決策がないことがわかりました。例外メッセージのさまざまな部分に取り組み、以下で分析しました。

分析:

  1. SSLException:JDKのjavax.net.sslパッケージに実装されているSSL(Secure Socket Layer)で例外が発生しました(openJDK/oracleJDK/AndroidSDK
  2. Read error ssl=# I/O error during system call:セキュアソケットからの読み取り中にエラーが発生しました。ネイティブシステムライブラリ/ドライバーを使用中に発生しました。すべてのプラットフォームsolaris、Windowsなどには、SSLによって使用される独自のソケットライブラリがあることに注意してください。 WindowsはWINSOCKライブラリを使用します。
  3. Connection reset by peer:このメッセージはシステムライブラリによって報告されます(SolarisはECONNRESETを報告し、WindowsはWSAECONNRESETを報告します。既存の接続が強制的に使用されたため、データ転送で使用されたソケットは使用できなくなりましたリモートホストによって閉じられます。ホストとクライアントの間に新しい安全なパスを作成する必要があります

理由:

問題を理解し、接続がリセットされた理由を見つけようとしましたが、以下の理由を思いつきました。

  • リモートホスト上のピアアプリケーションが突然停止した、ホストが再起動した、ホストまたはリモートネットワークインターフェイスが無効になった、またはリモートホストがハードクローズを使用した。
  • このエラーは、1つ以上の操作の進行中にキープアライブアクティビティが障害を検出したために接続が切断された場合にも発生することがあります。進行中の操作はNetwork dropped connection on reset(On Windows(WSAENETRESET))で失敗し、後続の操作はConnection reset by peer(On Windows(WSAECONNRESET))で失敗します。
  • ターゲットサーバーがファイアウォールで保護されている場合(ほとんどの場合に当てはまる)、ポートに関連付けられた存続時間(TTL)またはタイムアウトにより、idle指定されたタイムアウトでの接続。 これは私たちの興味のあるものです

解像度:

  1. サービスの突然の停止、再起動、ネットワークインターフェイスの無効化などのサーバー側のイベントは、いかなる手段でも処理できません。
  2. サーバー側で、指定されたポートのファイアウォールを、より高い存続時間(TTL)または3600秒などのタイムアウト値で構成します。
  3. クライアントはできます 「試して」 Connection reset by peerを回避または削減するためにネットワークをアクティブに保ちます。
  4. 通常、進行中のネットワークトラフィックは接続を維持し、問題/例外は頻繁には見られません。 強力なWifiは、Connection reset by peerの可能性が最も低い
  5. モバイルネットワークで 2G、3G、4G パケットデータの配信が断続的でモバイルネットワークの可用性に依存する場合、サーバー側のTTLタイマーをリセットせず、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の例外メッセージを確認します
  • 例外が見つかった場合は、ダウンロード/読み取りの進行状況を保存し、新しい接続を作成します。
  • 可能であればダウンロードを再開するか、またはダウンロードを再開します

詳細がお役に立てば幸いです。ハッピーコーディング...

89
Devendra Vaja

Nginxを使用して同様の問題が発生する場合、これが役立つ場合があります。

この sslTesturl でドメインをスキャンし、デバイスバージョンで接続が許可されているかどうかを確認します。

下位バージョンのデバイス(<Android 4.4.2など)がTLSサポートのために接続できない場合は、これをNginx構成ファイルに追加してみてください。

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
11
jayiitb

今朝からこの同じ問題が発生しましたが、解決しました...これが役立つことを願っています...

IIS 8のSSL

  1. 昨日はすべて正常に機能しており、昨夜、SSLはIISサイトで更新されました。
  2. SSLへのサイトバインドをチェックアウトする際、IIS8に新しいチェックボックスサーバー名の表示が必要があることに気付きましたが、チェックされませんでしたそれを有効にするために先行しました。
  3. それが問題を引き起こしました。
  4. IISに戻り、チェックボックスを無効にしました。..問題は解決しました!!!!

お役に立てれば!!!

5
Jorge Navarro

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

D/OkHttp:<-HTTP失敗:javax.net.ssl.SSLException:SSLハンドシェイクの中止:ssl = 0x64e3c938:システムコール中のI/Oエラー、ピアによる接続のリセット

1
tejraj

このエラーメッセージの別の考えられる原因は、HTTPメソッドがサーバーまたはロードバランサーによってブロックされている場合です。

未使用のHTTPメソッドをブロックするのは 標準セキュリティ慣行 のようです。 HEADがロードバランサーによってブロックされていたため、これに遭遇しました(しかし、奇妙なことに、負荷分散されたサーバーのすべてではなく、一部の場合にのみ失敗しました)。 GETメソッドを使用するように一時的に変更することで、リクエスト自体が正常に機能することをテストできました。

IOSのエラーコードは次のとおりでした:アプリコードの要求エラー:エラードメイン= NSURLErrorDomainコード= -1005「ネットワーク接続が失われました。」

0
Mykaelos