Отбрасывание Java половина пакетов UDP

У меня есть простая клиент-серверная установка. Сервер находится в C и клиенте, который запрашивает сервер, Java.

Моя проблема состоит в том, что, когда я отправляю интенсивные пропускной способностью данные по соединению, такому как Видеокадры, это приезжает к половине пакетов. Я удостоверяюсь, что правильно фрагментирую udp пакеты на стороне сервера (udp, имеет макс. длину полезной нагрузки 2^16). Я проверил, что сервер отправляет пакеты (printf результат sendto ()). Но Java, кажется, не получает половину данных.

Кроме того, когда я переключаюсь на TCP, все видеокадры проходят, но задержка начинает расти, добавляя задержку нескольких секунд после нескольких секунд времени выполнения.

Действительно ли там что-нибудь очевидно, что я отсутствую? Я просто, может казаться, не понимаю это.

6
задан stivlo 3 October 2011 в 16:57
поделиться

5 ответов

Получите сетевой инструмент, например Wireshark , чтобы вы могли видеть, что происходит в сети.

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

9
ответ дан 8 December 2019 в 17:20
поделиться

Любой протокол приложений на основе UDP неизбежно будет подвержен потере, переупорядочиванию и (в некоторых случаях) дублированию пакетов. «U» в UDP может означать «ненадежный» в ненадежном протоколе датаграмм. (Хорошо, это действительно означает «Пользователь» ... но это, безусловно, хороший способ запомнить характеристики UDP.)

Потери UDP-пакетов обычно происходят из-за того, что ваш трафик превышает емкость буферизации одного или нескольких «переходов». "между сервером и клиентом. Когда это происходит, пакеты отбрасываются ... и, поскольку вы используете UDP, на уровне транспортного протокола нет уведомления о том, что это происходит.

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

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

EDIT - на основе комментарий ОП, причина его проблемы заключалась в том, что клиент не "слушал" в течение определенного периода, в результате чего пакеты (предположительно) отбрасывались ОС клиента. Способ решения этой проблемы:

  1. использовать выделенный поток Java, который просто считывает пакеты и ставит их в очередь для обработки, а

  2. увеличивает размер очереди пакетов ядра для сокета.

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

РЕДАКТИРОВАТЬ 2 - Есть некоторые споры о том, подвержен ли UDP дублированию. Несомненно, UDP не имеет врожденного обнаружения или предотвращения дублирования. Но верно также и то, что структура маршрутизации IP-пакетов, которой является Интернет, вряд ли будет спонтанно дублировать пакеты.Таким образом, дубликаты, если они возникают, скорее всего, возникнут из-за того, что отправитель решил повторно отправить пакет UDP. Таким образом, на мой взгляд, хотя UDP подвержен проблемам с дубликатами, он не вызывает их как таковой ... если только нет ошибки в стеке протоколов ОС или в структуре IP.

3
ответ дан 8 December 2019 в 17:20
поделиться

IP поддерживает пакетов до 65535 байт, включая заголовок IP-пакета 20 байтов. UDP поддерживает дейтаграммы до 65507 байтов, плюс 20-байтовый IP-заголовок и 8-байтовый заголовок UDP 8 . Однако сетевой MTU - это практический предел, и не забывайте, что он включает не только эти 28 байтов, но и заголовок кадра Ethernet. Реальный реальный практический предел для нефрагментированного UDP - это минимальный MTU, равный 576 байтам, за вычетом всех накладных расходов.

0
ответ дан 8 December 2019 в 17:20
поделиться

Хотя UDP поддерживает пакеты длиной до 65535 байт ( включая заголовок UDP, который составляет 8 байтов - но см. Примечание 1), базовые транспорты между вами и пунктом назначения не поддерживают IP-пакеты, которые длинный. Например, кадры Ethernet имеют максимальный размер 1500 байт - с учетом накладных расходов для заголовков IP и UDP, это означает, что любой пакет UDP с длиной полезной нагрузки данных более 1450, вероятно, будет фрагментирован на несколько дейтаграмм IP.

Пакет UDP максимального размера будет фрагментирован как минимум на 45 отдельных дейтаграмм IP - и если какой-либо один из этих фрагментов будет потерян, весь пакет UDP будет потерян. Если ваш базовый коэффициент потери пакетов составляет 1%, ваше приложение увидит коэффициент потери около 36%!

Если вы хотите видеть меньше потерянных пакетов, не отправляйте огромные пакеты - ограничьте свои данные в каждом пакете примерно до 1400 байтов (или даже сделайте свое собственное «обнаружение MTU пути», чтобы определить максимальный размер, который вы можете безопасно отправить. без фрагментации).


  1. Конечно, UDP также подвержен ограничениям IP, и дейтаграммы IP имеют максимальный размер 65535, включая заголовок IP. Размер IP-заголовка варьируется от 20 до 60 байтов, поэтому максимальный объем данных приложения, передаваемых в пакете UDP, может составлять всего 65467.
2
ответ дан 8 December 2019 в 17:20
поделиться

Проблема может быть связана с заполнением буфера передачи в UDPSocket. Отправляйте только количество байтов за один раз, указанное UDPSocket.getSendBufferSize () . Используйте setSendBufferSize (int size) , чтобы увеличить это значение.

Если #send () используется для отправки пакета DatagramPacket, размер которого превышает значение параметра SO_SNDBUF, то это зависит от реализации, если пакет отправлено или выброшено.

0
ответ дан 8 December 2019 в 17:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: