android - llamadas - llamar por wifi a celular
javax.net.ssl.SSLException: Error de lectura: ssl=0x9524b800: Error de E/S durante la llamada al sistema, restablecimiento de la conexión por parte del par (5)
Nuestros clientes están comenzando a ver cientos de estos "Error de excepción SSLE - Restablecimiento de la conexión por pares" en las últimas semanas y no puedo entender por qué
-
Estamos usando Retrofit con okhttp, sin configuración especial
public class OkHttpClientProvider implements IOkHttpClientProvider { OkHttpClient okHttpClient; public OkHttpClientProvider() { this.okHttpClient = createClient(); } public OkHttpClient getOkHttpClient() { return this.okHttpClient; } private OkHttpClient createClient() { return new OkHttpClient(); } }
El proveedor de cliente anterior es un singleton. El RestAdapter está construido usando este cliente inyectado (usamos daga) -
RestAdapter.Builder restAdapterBuilder = new RestAdapter.Builder()
.setConverter(converter)
.setEndpoint(networkRequestDetails.getServerUrl())
.setClient(new OkClient(okHttpClientProvider.getOkHttpClient()))
.setErrorHandler(new NetworkSynchronousErrorHandler(eventBus))
);
Basado en soluciones de desbordamiento de pila lo que he descubierto:
-
La duración de mantener vivo en el servidor es de 180 segundos, OkHttp tiene un valor predeterminado de 300 segundos
-
El servidor devuelve "Conexión: cerrar" en su encabezado pero la solicitud del cliente envía "Conexión: keepAlive"
-
El servidor admite TLS 1.0 / 1.1 / 1.2 y usa Open SSL
-
Nuestros servidores se han mudado a otro proveedor de alojamiento recientemente en otra geografía, así que no sé si se trata de fallas de DNS o no
-
Hemos intentado ajustar cosas como keepAlive, OpenSSL reconfigurado en el servidor, pero por alguna razón el cliente de Android sigue recibiendo este error
-
Ocurre inmediatamente sin demora cuando intentas usar la aplicación para publicar algo o tirar para actualizar (ni siquiera va a la red o tiene un retraso antes de que ocurra esta excepción, lo que implicaría que la conexión ya está interrumpida). Pero intentarlo varias veces de alguna manera "lo arregla" y tenemos éxito. Sucede de nuevo más tarde
-
Hemos invalidado nuestras entradas de DNS en el servidor para ver si esto es lo que lo causó, pero eso no ha ayudado
-
Ocurre principalmente en LTE, pero también lo he visto en Wifi
No quiero desactivar mantener vivo porque la mayoría de los clientes modernos no hacen eso. También estamos usando OkHttp 2.4 y este es un problema en los dispositivos de sándwich posteriores a Ice Cream, así que espero que se encargue de estos problemas de red subyacentes. El cliente iOS también recibe estas excepciones, pero cerca de 100 veces menos (el cliente iOS usa AFNetworking 2.0). Estoy luchando por encontrar cosas nuevas para probar en este momento, ¿alguna ayuda / idea?
Actualización: agregar seguimiento de pila completa a través de 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)
]}
Android Admite la implementación de SSL de forma predeterminada, excepto Android N (nivel de API 24) e inferior a Android 5.1 (nivel de API 22)
Recibí el error al realizar la llamada a la API por debajo de los dispositivos del nivel 22 de la API después de implementar SSL en el lado del servidor;
eso fue mientras se creaba el objeto de cliente OkHttpClient, y se solucionó agregando la clase OkHttpClient.Builder del método connectionSpecs ().
el error recibido fue
error de respuesta: javax.net.ssl.SSLException: protocolo de enlace SSL abortado: ssl = 0xb8882c00: error de E / S durante la llamada al sistema, restablecimiento de la conexión por parte del par
así que arreglé esto agregando el cheque como
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);
}
}
También para Android N (API nivel 24); Estaba recibiendo el error al hacer la llamada HTTP como
HTTP FALLIDO: javax.net.ssl.SSLHandshakeException: Handshake falló
y esto se soluciona agregando la verificación para Android 7 en particular, como
if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.N){
// Do something for naugat ; 7
okb.connectionSpecs(Collections.singletonList(getSpec()));
}
Entonces mi objeto OkHttpClient final será como:
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();
La función getSpecsBelowLollipopMR1 será,
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;
}
}
La clase Tls12SocketFactory se encontrará en el siguiente enlace (comentario de gotev):
https://github.com/square/okhttp/issues/2372
Para obtener más ayuda al agregar algunos enlaces a continuación, esto lo ayudará en detalle,
https://developer.android.com/training/articles/security-ssl
Otra posible causa de este mensaje de error es si el servidor HTTP o el equilibrador de carga bloquean el Método HTTP.
Parece ser una práctica de seguridad estándar bloquear los métodos HTTP no utilizados. Nos encontramos con esto porque HEAD estaba siendo bloqueado por el equilibrador de carga (pero, curiosamente, no todos los servidores con equilibrio de carga, lo que ocasionó que fallara solo algunas veces). Pude probar que la solicitud en sí misma funcionó bien cambiándola temporalmente para usar el método GET.
El código de error en iOS fue: Error al solicitar el código de la aplicación: Error Domain = NSURLErrorDomain Code = -1005 "Se perdió la conexión de red".
Recientemente me enfrenté al problema mientras trabajaba en un código heredado. Después de buscar en Google, descubrí que el problema está en todas partes pero sin ninguna resolución concreta. Trabajé en varias partes del mensaje de excepción y analicé a continuación.
Análisis:
-
SSLException
: la excepción ocurrió con SSL (Secure Socket Layer), que se implementa en el paquetejavax.net.ssl
del JDK (openJDK/oracleJDK/AndroidSDK
) -
Read error ssl=# I/O error during system call
: se produjo un error al leer desde el socket seguro. Sucedió mientras usaba las bibliotecas / controladores del sistema nativo. Tenga en cuenta que todas las plataformas solaris, Windows, etc. tienen sus propias bibliotecas de sockets que utiliza SSL. Windows usa la biblioteca WINSOCK. -
Connection reset by peer
: la biblioteca del sistema informa este mensaje (Solaris informaECONNRESET
, Windows informaWSAECONNRESET
), que el socket utilizado en la transferencia de datos ya no se puede usar porque el host remoto cerró a la fuerza una conexión existente. Uno necesita crear una nueva ruta segura entre el host y el cliente
Razón:
Comprendiendo el problema, trato de encontrar la razón detrás del restablecimiento de la conexión y se me ocurrieron las siguientes razones:
- La aplicación del mismo nivel en el host remoto se detiene repentinamente, el host se reinicia, el host o la interfaz de red remota se deshabilita o el host remoto utiliza un cierre completo.
-
Este error también puede producirse si una conexión se interrumpió debido a una actividad de mantenimiento activo que detecta una falla mientras una o más operaciones están en progreso.
Las operaciones que estaban en progreso fallan con la
Network dropped connection on reset(On Windows( WSAENETRESET ))
y las operaciones posteriores fallan con elConnection reset by peer(On Windows( WSAECONNRESET ))
. - Si el servidor de destino está protegido por Firewall, lo cual es cierto en la mayoría de los casos, el tiempo de vida (TTL) o el tiempo de espera asociado con el puerto cierra por la fuerza la conexión inactiva en un tiempo de espera determinado. esto es algo de nuestro interés
Resolución:
- Los eventos en el lado del servidor, como la interrupción repentina del servicio, el reinicio, la interfaz de red deshabilitada no pueden manejarse de ninguna manera.
- En el lado del servidor, configure el firewall para el puerto dado con el mayor tiempo de vida (TTL) o valores de tiempo de espera como 3600 segundos.
-
Los clientes pueden
"intentar"
mantener la red activa para evitar o reducir el
Connection reset by peer
laConnection reset by peer
. -
Normalmente, el tráfico de red en curso mantiene viva la conexión y el problema / excepción no se ve con frecuencia.
Wifi fuerte tiene menos posibilidades de
Connection reset by peer
de laConnection reset by peer
. -
Con las redes móviles
2G, 3G y 4G,
donde la entrega de paquetes de datos es intermitente y depende de la disponibilidad de la red móvil, es posible que no restablezca el temporizador TTL en el lado del servidor y que la
Connection reset by peer
.
Estos son los términos sugeridos para establecer en varios foros para resolver el problema.
-
ConnectionTimeout:
usa solo en el tiempo de espera para realizar la conexión. Si el host tarda en conectarse, un valor más alto de esto hace que el cliente espere la conexión. -
SoTimeout
: Socket timeout: indica el tiempo máximo dentro del cual se recibe un paquete de datos para considerar la conexión como activa. Si no se reciben datos dentro del tiempo dado, se supone que la conexión está detenida / interrumpida. -
Linger
: hasta qué hora no se debe cerrar el socket cuando los datos se ponen en cola para ser enviados y la función de cierre del socket se llama en el socket. -
TcpNoDelay
: ¿Desea deshabilitar el búfer que contiene y acumula los paquetes TCP y los envía una vez que se alcanza un umbral? Establecer esto en verdadero omitirá el almacenamiento en búfer TCP para que cada solicitud se envíe de inmediato. Las ralentizaciones en la red pueden ser causadas por un aumento en el tráfico de la red debido a una transmisión de paquetes más pequeña y frecuente.
Por lo tanto, ninguno de los parámetros anteriores ayuda a mantener viva la red y, por lo tanto, no es efectiva.
Encontré una configuración que puede ayudar a resolver el problema que es esto funciones
setKeepAlive(true)
setSoKeepalive(HttpParams params, enableKeepalive="true")
¿Cómo resolví mi problema?
-
Establezca
HttpConnectionParams.setSoKeepAlive(params, true)
-
SSLException
la excepciónSSLException
y compruebe el mensaje de excepción paraConnection reset by peer
- Si se encuentra una excepción, almacene el progreso de descarga / lectura y cree una nueva conexión.
- Si es posible, reanude la descarga / lectura; de lo contrario, reinicie la descarga
Espero que los detalles ayuden. Feliz codificación ...
Si usa
Nginx
y tiene un problema similar, esto podría ayudar:
Escanee su dominio en este sslTesturl y vea si se permite la conexión para la versión de su dispositivo.
Si los dispositivos de versiones inferiores (como <Android 4.4.2, etc.) no pueden conectarse debido a la compatibilidad con TLS, intente agregar esto a su archivo de configuración de Nginx,
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
tuvimos este mismo problema a partir de esta mañana y lo resolvimos ... espero que esto ayude ...
SSL en IIS 8
- Todo funcionaba bien ayer y anoche nuestro SSL se actualizó en el sitio IIS.
- Mientras revisaba el sitio Los enlaces al SSL notaron que IIS8 tenía una nueva casilla de verificación Requerir indicación del nombre del servidor , pero no se verificó antes de habilitarlo.
- Eso desencadenó el problema.
- Volví a IIS, deshabilité la casilla de verificación ... ¡¡¡Problema resuelto !!!!
¡¡¡Espero que esto ayude!!!