У меня есть веб-приложение и клиент, написанные на Java. Что бы это ни стоило, клиент и сервер находятся в Windows. Клиент отправляет запросы HTTP GET через Apache HttpClient. Сервер блокируется на срок до минуты, и если в течение этой минуты клиенту не поступило никаких сообщений, сервер возвращает HTTP 204 No Content. В противном случае, как только сообщение готово для клиента, оно возвращается с телом HTTP 200 OK.
Вот что меня озадачило: время от времени для определенного подмножества клиентов (всегда клиентов с заведомо ненадежным сетевым подключением) клиент выдает GET, сервер получает и обрабатывает GET, но клиент сидит навсегда. Включив логи отладки для клиента, я вижу, что HttpClient все еще ждет самую первую строчку ответа.
На сервере нет исключений, по крайней мере, нигде ничего не зарегистрировано, ни Tomcat, ни мое веб-приложение. Судя по журналам отладки, есть все признаки того, что сервер успешно ответил клиенту. Однако клиент не показывает никаких признаков получения чего-либо. Клиент зависает на неопределенное время в HttpClient.executeMethod. Это становится очевидным после того, как время сеанса истекает, и клиент предпринимает действия, которые заставляют другой поток выдавать HTTP POST. Конечно, POST завершается ошибкой, потому что срок действия сеанса истек. В некоторых случаях между истечением срока действия сеанса и отправкой клиентом POST и обнаружением этого факта прошло часы. Все это время executeMethod
все еще ждет строку ответа HTTP.
Когда я использую WireShark, чтобы увидеть, что на самом деле происходит на уровне проводов, этого сбоя не происходит. То есть этот сбой произойдет в течение нескольких часов для конкретных клиентов, но когда WireShark запущен на обоих концах, эти же клиенты будут работать всю ночь, 14 часов, без сбоя.
Кто-нибудь еще сталкивался с чем-то подобным? Что в мире может вызвать это? Я думал, что TCP/IP гарантирует доставку пакетов даже при кратковременных сетевых сбоях. Если я устанавливаю SO_TIMEOUT и немедленно повторяю запрос по тайм-ауту, повторная попытка всегда завершается успешно. (Конечно, я сначала отменить запрос с истекшим временем ожидания и разорвать соединение, чтобы гарантировать использование нового сокета.)
Мысли? Идеи? Есть ли какой-либо параметр TCP/IP, доступный для Java, или параметр реестра в Windows, который активирует более агрессивные повторные попытки TCP/IP для потерянных пакетов?