У нас возникают проблемы каждый день с одним из наших клиентов, чьи подключения отключены через определенное время. Исключение на стороне клиента показывает сообщение «Прочитанное время». Поскольку мы не используем тайм-ауты сокетов в нашем Java-приложении (мы используем значения по умолчанию 0), наша первая мысль заключается в том, что таймауты клиента должны поступать от прокси-сервера или маршрутизатора на их стороне. Их ИТ-отдел изучает эту проблему.Закрытие входного потока сокета занимает слишком много времени.
Однако, когда соединение прерывается, наше клиентское приложение закрывает сокет, а затем устанавливает новое соединение с нашим сервером. После приема нового соединения от того же клиента сервер начнет операцию очистки старого соединения, прежде чем он начнет использовать новый. Эта очистка происходит, когда сервер обнаруживает EOS или любое другое исключение для чтения или когда новое соединение принимается одним и тем же клиентом, а старый не был очищен по какой-либо причине (это происходит здесь из-за сбоя нашего сервера для обнаружения EOS). Эта операция очистки включает в себя фактически некоторую регистрацию, очистку различных структур данных маршрутизации и окончательное закрытие входных и выходных потоков. В этот момент мы заметили, что закрытие входного потока старых блоков сокетов в течение 15 минут и времени всегда одно и то же. Как вы можете понять, все идет не так, потому что новое соединение начинает голодать, и одна и та же проблема начинается с начала несколько раз.
Теперь, я полагаю, что наш сокет на стороне сервера страдает неопределенным FIN_WAIT_2 или TIME_WAIT, в котором сокет остается в одном из этих состояний без получения необходимых ACK (возможно, они отбрасываются), которые могут перемещаться это состояние ЗАКРЫТО. Хотя наш сервер не был первым, кто нарушил соединение, я полагаю, что это прокси-сервер или маршрутизатор со стороны клиента, который, возможно, инициировал и сделал его похожим на наш сервер. Я прочитал, что настройка SO_LINGER на стороне сервера на 0 может помочь в такой ситуации (хотя в целом это не рекомендуется). FYI: мы до сих пор не испортили опцию SO_LINGER, но мы думаем сделать это из-за проблемы.
Не могли бы вы объяснить мне, правда ли эта теория? Более того, почему операция закрытия сокета занимает 15 минут? Это намного выше обычной продолжительности жизни 2 * MSL (максимальный срок службы сегмента), которая, как предполагается, является временем, в течение которого сокет ждет закрытия. Должно ли мы установить значение параметра SO_LINGER (метод setSoLinger в Java) на значение, превышающее 0? В любом случае клиент уже прервал соединение на другой стороне и, таким образом, установив опцию linger на 0 непосредственно перед закрытием сокета, не приведет к какому-либо другому исключению или неправильному состоянию на стороне клиента. Кроме того, есть ли у вас какие-либо инструменты, с помощью которых мы могли бы моделировать упавшие пакеты в нашей среде?
Код, создающий и очищающий сокет, не является чем-то особенным. Вот отрывок:
Socket socket = new Socket(ipAddress, port);
OutputStream dataOutputStream = new BufferedOutputStream(socket.getOutputStream(), 64000);
InputStream dataInputStream = new BufferedInputStream(socket.getInputStream(), 64000);
код закрытия потока
try {
if (dataInputStream != null) {
LOGGER.info("Going to close input stream....");
dataInputStream.close();
}
} finally {
if (dataOutputStream != null) {
LOGGER.info(".closeReaderWriter()", "Going to close output stream...");
dataOutputStream.close();
}
}
Можете ли вы поделиться кодом, в котором вы создаете экземпляр сокета, где вы закрываете сокет, и где вы пытаетесь снова его повторно подключить? – Rainbolt