Что может заставить TCP / IP отбрасывать пакеты без разрыва соединения? - PullRequest
9 голосов
/ 25 апреля 2009

У меня есть веб-приложение и клиент, оба написаны на Java. Для чего это стоит, клиент и сервер оба на Windows. Клиент выдает HTTP GET через Apache HttpClient . Сервер блокируется на срок до минуты, и если в течение этой минуты клиенту не поступило сообщений, сервер возвращает HTTP 204 Нет содержимого. В противном случае, как только сообщение готово для клиента, оно возвращается с телом 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 для потерянных пакетов?

Ответы [ 6 ]

8 голосов
/ 25 апреля 2009

Вы абсолютно уверены, что сервер успешно отправил ответ клиентам, которые, по-видимому, перестали работать? Под этим я подразумеваю, что сервер отправил ответ, а клиент получил ответ обратно на сервер. Вы должны увидеть это, используя wireshark на стороне сервера. Если вы уверены, что это произошло на стороне сервера, а клиент по-прежнему ничего не видит, вам нужно посмотреть дальше по цепочке с сервера. Существуют ли прокси / обратные прокси-серверы или NAT?

Транспорт TCP считается надежным протоколом, но он не гарантирует доставку. Стек TCP / IP вашей ОС будет очень стараться доставлять пакеты на другой конец с помощью повторных передач TCP. Вы должны увидеть это в wireshark на стороне сервера, если это происходит. Если вы видите чрезмерные повторные передачи TCP, это, как правило, проблема сетевой инфраструктуры - то есть плохое или неправильно настроенное оборудование / интерфейсы. Повторные передачи TCP отлично подходят для коротких прерываний сети, но плохо работают в сети с более длительным прерыванием. Это связано с тем, что стек TCP / IP будет отправлять повторные передачи только после истечения таймера. Этот таймер обычно удваивается после каждой неудачной повторной передачи. Это сделано для того, чтобы избежать переполнения и без того проблемной сети повторными передачами. Как вы можете себе представить, это обычно вызывает у приложений всевозможные проблемы тайм-аута.

В зависимости от топологии вашей сети вам также может понадобиться разместить зонды / wireshark / tcpdump в других промежуточных точках сети. Это, вероятно, займет некоторое время, чтобы выяснить, куда ушли пакеты.

Будь я на вашем месте, я бы продолжал контролировать Wireshark со всех концов, пока проблема не возникнет снова. Это, скорее всего, будет. Но, похоже, что вы в конечном итоге найдете то, что вы уже упомянули - ненадежное оборудование. Если об исправлении нестабильного оборудования не может быть и речи, вам может потребоваться просто встроить дополнительные тайм-ауты на уровне приложения и повторить попытку, чтобы попытаться решить проблему в программном обеспечении. Похоже, вы начали идти по этому пути.

2 голосов
/ 23 июня 2009

Если вы используете долго выполняющиеся GET, вы должны установить время ожидания на стороне клиента в два раза больше времени ожидания сервера, как вы обнаружили.

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

Клиент обнаружит, что сокет закрыт на стороне сервера, как только он отправит больше данных на этот сокет, и сервер отклонит эти новые данные и закроет сокет.

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

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

2 голосов
/ 25 апреля 2009

Если забыть очистить или закрыть сокет на стороне хоста, это может периодически вызывать этот эффект для коротких ответов в зависимости от времени, которое может зависеть от наличия какого-либо механизма мониторинга.

В особенности, если забыть закрыть, сокет будет болтаться, пока GC не вернется к его освобождению и не вызовет finalize ().

1 голос
/ 25 апреля 2009

Я не видел этого как такового, но я видел похожие проблемы с большими дейтаграммами UDP, вызывающими фрагментацию IP, которая приводит к перегрузке и, в конечном итоге, к потере кадров Ethernet. Поскольку это TCP / IP, я не ожидал, что фрагментация IP будет большой проблемой, поскольку это потоковый протокол.

Стоит отметить, что TCP не гарантирует доставку! Не может. Он гарантирует, что если вы отправите байт A , за которым следует байт B , то вы никогда не получите байт B до получения байта A .

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

0 голосов
/ 25 апреля 2009

Если вы теряете данные, это, скорее всего, связано с программной ошибкой в ​​библиотеке чтения или записи.

0 голосов
/ 25 апреля 2009

Может ли на этих компьютерах установлен вирус / вредоносное ПО? При использовании wireshark устанавливается winpcap (http://www.winpcap.org/), который может отменять изменения, внесенные вредоносной программой (или вредоносная программа может просто обнаружить, что она отслеживается, и не предпринимать ничего подозрительного).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...