java.net.SocketException: сброс подключения

128

Я получаю следующую ошибку при чтении из сокета. Я делаю readInt()на этом InputStream, и я получаю эту ошибку. Изучая документацию, можно предположить, что клиентская часть соединения закрыла соединение. В этом сценарии я являюсь сервером.

У меня есть доступ к файлам журнала клиента, и он не закрывает соединение, и на самом деле его файлы журнала предполагают, что я закрываю соединение. Кто-нибудь знает, почему это происходит? Что еще проверить? Возникает ли это, когда есть местные ресурсы, которые, возможно, достигают пороговых значений?


Замечу, что у меня есть такая строка:

socket.setSoTimeout(10000);

непосредственно перед readInt(). Для этого есть причина (длинная история), но просто любопытно, есть ли обстоятельства, при которых это могло бы привести к указанной ошибке? У меня есть сервер, работающий в моей IDE, и я случайно оставил свою IDE застрявшей в точке останова, и затем я заметил, что те же самые ошибки начали появляться в моих собственных журналах в моей IDE.

В любом случае, просто упоминание об этом, надеюсь, не отвлекающий маневр. :-(

голубоватый
источник
У вас есть следы стека с обеих сторон? Не могли бы вы немного подробнее описать сетевую архитектуру? (Через дикий Интернет? На одной машине? Где-то посередине?) Это происходит постоянно? Или с перерывами?
Стю Томпсон,

Ответы:

116

Есть несколько возможных причин.

  1. Другой конец намеренно сбросил соединение, что я здесь не буду описывать. Прикладное программное обеспечение делает это редко и, как правило, неправильно, но для коммерческого программного обеспечения это известно.

  2. Чаще всего это вызвано записью в соединение, которое другой конец уже нормально закрыл. Другими словами, ошибка протокола приложения.

  3. Это также может быть вызвано закрытием сокета, когда в приемном буфере сокета есть непрочитанные данные.

  4. В Windows «программное обеспечение вызвало прерывание соединения», что не то же самое, что «сброс соединения», вызвано сетевыми проблемами при отправке с вашего конца. Об этом есть статья в базе знаний Microsoft.

Маркиз Лорн
источник
@MattLyons Спасибо. Есть гораздо лучшие статьи MSDN, чем эта. Честно говоря, мне трудно в это поверить. Соединение даже не будет существовать, пока не будут установлены правильный исходный и целевой IP-адреса. В статьях MSDN, которые я видел, говорится о постоянных сетевых ошибках, связанных с задержкой соединения.
Маркиз Лорн,
48

Сброс соединения означает просто получение TCP RST. Это происходит, когда ваш партнер получает данные, которые он не может обработать, и для этого могут быть разные причины.

Самый простой - это когда вы закрываете сокет, а затем записываете больше данных в выходной поток. Закрывая сокет, вы сказали своему партнеру, что вы закончили говорить, и он может забыть о вашем соединении. Когда вы все равно отправляете в этот поток больше данных, одноранговый узел отклоняет их с помощью RST, чтобы вы знали, что он не слушает.

В других случаях вмешивающийся межсетевой экран или даже сам удаленный хост могут «забыть» о вашем TCP-соединении. Это может произойти, если вы не отправляете никаких данных в течение длительного времени (2 часа - обычный тайм-аут) или из-за того, что одноранговый узел был перезагружен и потерял информацию об активных соединениях. Отправка данных по одному из этих несуществующих соединений также вызовет RST.


Обновление в ответ на дополнительную информацию:

Внимательно посмотрите на то, как вы работаете с SocketTimeoutException. Это исключение возникает, если превышен настроенный тайм-аут при блокировании операции сокета. Состояние самого сокета не изменяется при возникновении этого исключения, но если ваш обработчик исключений закрывает сокет, а затем пытается записать в него, вы будете в состоянии сброса соединения. setSoTimeout()предназначен для того, чтобы дать вам чистый способ прервать read()операцию, которая в противном случае могла бы заблокироваться навсегда, без каких-либо грязных вещей, таких как закрытие сокета из другого потока.

Эриксон
источник
Неправильно в нескольких отношениях. Сборка мусора и завершение процесса вызывают правильное закрытие, а не сброс, но закрытие с последующей записью одноранговым узлом может вызвать сброс, а не EOS. SocketTimeoutExceptions возникают, только если читатель установил тайм-аут чтения.
Marquis of Lorne
И это не всегда означает, что RST был получен. Это также может означать, что он был создан этой стороной.
Marquis of Lorne,
17

Всякий раз, когда у меня возникают такие странные проблемы, я обычно сажусь с таким инструментом, как WireShark, и смотрю на необработанные данные, передаваемые туда и обратно. Вы можете быть удивлены, когда что-то отключается, и вы получаете уведомление только тогда, когда пытаетесь прочитать.

GEOCHET
источник
9

Стыдно это говорить, но когда у меня возникла эта проблема, я просто по ошибке закрывал соединение, прежде чем прочитал все данные. В случаях, когда возвращались небольшие строки, это работало, но, вероятно, это было связано с тем, что весь ответ был буферизован, прежде чем я его закрыл.

В случаях, когда возвращалось большее количество текста, вызывалось исключение, поскольку возвращалось больше буфера.

Вы можете проверить эту оплошность. Помните, что открытие URL-адреса похоже на файл, обязательно закройте его (освободите соединение), как только он будет полностью прочитан.

Скотт С.
источник
9

Вам следует очень внимательно изучить всю трассировку,

У меня есть приложение для серверного сокета, и я исправил java.net.SocketException: Connection resetслучай.

В моем случае это происходит при чтении из Socketобъекта clientSocket, который по какой-то причине закрывает свое соединение. (Потеря сети, сбой брандмауэра или приложения или запланированное закрытие)

На самом деле я повторно устанавливал соединение, когда у меня возникла ошибка при чтении из этого объекта Socket.

Socket clientSocket = ServerSocket.accept();
is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
int readed = is.read(); // WHERE ERROR STARTS !!!

Интересно то, что for my JAVA Socketесли клиент подключается к my ServerSocketи закрывает свое соединение без отправки чего-либо, is.read()вызывает себя рекурсивно. Похоже, что из-за того, что вы находитесь в бесконечном цикле while для чтения из этого сокета, вы пытаетесь читать из закрытого соединения. Если вы используете что-то подобное ниже для операции чтения;

while(true)
{
  Receive();
}

Затем вы получаете stackTrace примерно так, как показано ниже.

java.net.SocketException: Socket is closed
    at java.net.ServerSocket.accept(ServerSocket.java:494)

Я просто закрыл ServerSocket и обновил свое соединение и ждал дальнейших входящих клиентских подключений.

String Receive() throws Exception
{
try {                   
            int readed = is.read();
           ....
}catch(Exception e)
{
        tryReConnect();
        logit(); //etc
}


//...
}

Это восстанавливает мое соединение при потере неизвестного клиентского сокета

private void tryReConnect()
        {
            try
            {
                ServerSocket.close();
                //empty my old lost connection and let it get by garbage col. immediately 
                clientSocket=null;
                System.gc();
                //Wait a new client Socket connection and address this to my local variable
                clientSocket= ServerSocket.accept(); // Waiting for another Connection
                System.out.println("Connection established...");
            }catch (Exception e) {
                String message="ReConnect not successful "+e.getMessage();
                logit();//etc...
            }
        }

Я не мог найти другого способа, потому что, как вы видите на изображении ниже, вы не можете понять, потеряно соединение или нет, без a try and catch, потому что все кажется правильным. Я получил этот снимок, пока делал Connection resetнепрерывно.

введите описание изображения здесь

Давут Гюрбюз
источник
6

У меня была такая же ошибка. Я нашел решение проблемы. Проблема заключалась в том, что клиентская программа завершала работу до того, как сервер прочитал потоки.

kml_ckr
источник
Само по себе это не вызовет этого исключения.
Marquis of Lorne,
это произойдет, если System.exit (0) убьет программу и никто не вызовет socket.close (), поскольку соединение находится в плохом состоянии и не было закрыто должным образом. ооочень правильнее сказать, что у него есть клиентская программа, которая завершает работу без закрытия сокетов;) что плохо и должно быть исправлено.
Дин Хиллер
1
@DeanHiller Нет, это не так. Операционная система закроет сокет так же, как и приложение.
Marquis of Lorne
@EJP .... Я не уверен ... Я просто знаю, что мы могли бы воспроизвести это с помощью System.exit, но я не помню OS / config, как это было довольно давно ... вызов socket.close ( ) на сервере предотвратил сброс соединения и вёл себя более корректно.
Дин Хиллер
2
@DeanHiller Процесс чтения завершился до того, как процесс записи закончил запись.
Маркиз Лорн
4

У меня была эта проблема с системой SOA, написанной на Java. Я запускал и клиент, и сервер на разных физических машинах, и они долгое время работали нормально, затем эти неприятные сбросы подключения появились в журнале клиента, и в журнале сервера не было ничего странного. Перезапуск клиента и сервера не решил проблему. Наконец, мы обнаружили, что куча на стороне сервера была довольно заполнена, поэтому мы увеличили объем памяти, доступной для JVM: проблема решена! Обратите внимание, что в журнале не было OutOfMemoryError: памяти было мало, она не была исчерпана.

Pino
источник
2

Проверьте версию Java на вашем сервере. Это случилось со мной, потому что мой Weblogic 10.3.6 был на JDK 1.7.0_75, который был на TLSv1. Остальная конечная точка, которую я пытался использовать, отключает все, что ниже TLSv1.2.

По умолчанию Weblogic пытался согласовать самый надежный общий протокол. Подробнее см. Здесь: Проблемы с настройкой свойства системы https.protocols для HTTPS-соединений .

Я добавил подробное ведение журнала SSL, чтобы определить поддерживаемый TLS. Это означало, что для рукопожатия использовался TLSv1.
-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

Я решил эту проблему, разместив эту функцию в нашем JDK8-совместимом продукте, JDK8 по умолчанию использует TLSv1.2. Для тех, кто ограничен JDK7, я также успешно протестировал обходной путь для Java 7, обновившись до TLSv1.2. Я использовал этот ответ: Как включить TLS 1.2 в Java 7

Сумия
источник
Большое спасибо, вы показываете мне новое направление, чтобы исправить мою проблему. и наконец я нашел это дело !!!
Карл Ли
1

У меня также была эта проблема с программой Java, пытающейся отправить команду на сервер через SSH. Проблема заключалась в том, что машина выполняла код Java. У него не было разрешения на подключение к удаленному серверу. Метод write () работал нормально, но метод read () выдавал java.net.SocketException: сброс соединения. Я исправил эту проблему, добавив клиентский SSH-ключ к известным ключам удаленного сервера.

pmartin8
источник
0

По моему опыту, я часто сталкиваюсь со следующими ситуациями;

  1. Если вы работаете в корпоративной компании, обратитесь в службу безопасности и сети. Поскольку в запросах к внешним службам может потребоваться предоставить разрешение для соответствующей конечной точки.

  2. Другая проблема заключается в том, что срок действия сертификата SSL мог истечь на сервере, на котором работает ваше приложение.

bmck
источник