Javax.net.ssl.SSLException: Ошибка чтения: ssl = 0x9524b800: ошибка ввода-вывода во время системного вызова, соединение reset от пользователя
В течение последних двух недель наши клиенты начинают видеть 100 из этих "SSLException error - Connection reset by peer", и я не могу понять, почему
-
Мы используем Retrofit с okhttp, без специальной конфигурации
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: 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)
]}
Ответы
Ответ 1
Недавно я столкнулся с проблемой при работе над некоторым устаревшим кодом. После googling я обнаружил, что проблема повсюду, но без какой-либо конкретной резолюции. Я работал над различными частями сообщения об исключениях и анализировался ниже.
Анализ:
-
SSLException
: исключение произошло с SSL (Secure Socket Layer), который реализован в пакете javax.net.ssl
JDK (openJDK/oracleJDK/AndroidSDK
)
-
Read error ssl=# I/O error during system call
: Ошибка при чтении из сокета Secure. Это произошло при использовании собственных системных библиотек/драйверов. Обратите внимание: все платформы solaris, Windows и т.д. Имеют свои собственные библиотеки сокетов, которые используются SSL. Windows использует библиотеку WINSOCK.
-
Connection reset by peer
: это сообщение сообщается системной библиотекой (отчеты Solaris ECONNRESET
, отчеты Windows WSAECONNRESET
), что сокет, используемый при передаче данных, больше не используется, поскольку существующее соединение было принудительно закрыто удаленный узел. Нужно создать новый безопасный путь между хостом и клиентом.
Причина:
Понимая проблему, я пытаюсь найти причину подключения reset, и я пришел к следующим причинам:
- Одноранговое приложение на удаленном хосте внезапно остановлено, хост перезагружен, хост или удаленный сетевой интерфейс отключен, или удаленный хост использует жесткое закрытие.
- Эта ошибка может также возникнуть, если соединение было нарушено из-за активности keep-alive, обнаруживающей сбой при выполнении одной или нескольких операций. Выполняемые операции завершились неудачей с
Network dropped connection on reset(On Windows(WSAENETRESET))
и последующими операциями с Connection reset by peer(On Windows(WSAECONNRESET))
.
- Если целевой сервер защищен брандмауэром, что является истинным в большинстве случаев, время жизни (TTL) или тайм-аут, связанные с портом, принудительно закрывают незанятое соединение при заданном тайм-ауте. Это что-то интересное
Разрешение:
- События на стороне сервера, такие как внезапный останов обслуживания, перезагрузка, отключенный сетевой интерфейс, не могут быть обработаны никакими средствами.
- На стороне сервера настройте брандмауэр для данного порта с более высоким временем жизни (TTL) или значениями таймаута, например 3600 секунд.
- Клиенты могут "попробовать" поддерживать активную сеть, чтобы избежать или уменьшить
Connection reset by peer
.
- Обычно при запуске сетевого трафика поддерживается соединение, а проблема/исключение часто не видны. Сильный Wifi имеет наименьшие шансы
Connection reset by peer
.
- В мобильных сетях 2G, 3G и 4G, где доставка пакетных данных прерывистая и зависит от доступности мобильной сети, она может не reset таймера 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
- Если обнаружено исключение, сохраните процесс загрузки/чтения и создайте новое соединение.
- Если возможно, возобновите загрузку/чтение, перезапустите загрузку
Я надеюсь, что детали помогут. Счастливое кодирование...
Ответ 2
Если вы используете Nginx
и получаете аналогичную проблему, это может помочь:
Сканируйте свой домен на этом sslTesturl и проверьте, разрешено ли подключение для вашей версии устройства.
Если устройства с более низкой версией (например, Android 4.4.2 и т.д.) не могут подключиться из-за поддержки TLS, попробуйте добавить это в свой конфигурационный файл Nginx,
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
Ответ 3
У нас была такая же проблема, начиная с сегодняшнего утра, и она решена... надеюсь, что это поможет...
SSL на IIS 8
- Все работало хорошо вчера и вчера, наш SSL был обновлен на сайте IIS.
- При проверке сайта привязки к SSL заметили, что IIS8 имеет новый флажок "Требовать указание имени сервера" , он не был проверен так, чтобы ему предшествовали включите его.
- Это вызвало проблему.
- Вернулся в IIS, отключил флажок.... Проблема решена!!!!
Надеюсь, это поможет!!!
Ответ 4
Другая возможная причина для этого сообщения об ошибке заключается в том, что HTTP-метод блокируется сервером или балансировщиком нагрузки.
Кажется, что стандартная практика безопасности блокирует неиспользуемые методы HTTP. Мы столкнулись с этим, потому что HEAD блокировался балансировщиком нагрузки (но, как ни странно, не все серверы с балансировкой нагрузки, из-за которых он проваливался только некоторое время). Я смог проверить, что сам запрос работал нормально, временно изменив его, чтобы использовать метод GET.
Код ошибки в iOS был:
Ошибка запроса кода приложения: Ошибка домена = NSURLErrorDomain Code = -1005 "Сетевое соединение было потеряно".