«Правильный» способ отправки последовательности дейтаграмм UDP? - PullRequest
4 голосов
/ 20 мая 2009

У меня сложилось впечатление, что нестабильность UDP является свойством физического уровня, но, похоже, это не так:

Я пытаюсь отправить сообщение по UDP, которое разбито на последовательность пакетов. Идентификация сообщения и переупорядочение осуществляется неявно.

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

Теперь тот факт, что потери происходят даже на одной машине, заставляет меня задуматься, правильно ли я это делаю?

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

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

Если я добавил паузу (Sleep (...)) между peices, это сработает на 100%.

EDIT: Как и предполагали респонденты: пакеты просто отправляются слишком быстро, а ОС выполняет минимальную буферизацию. Это логично.

Итак, если я хотел бы запретить добавление подтверждения и повторной передачи в систему (тогда я мог бы просто использовать TCP), что мне делать? Каков наилучший способ улучшить коэффициент потери пакетов без сброса данных до уровней, которые могли бы быть выше?

РЕДАКТИРОВАТЬ 2: Мне пришло в голову, что проблема может заключаться не в переполнении буфера, а в недоступности буфера. Я использую async WSARecvFrom для получения, который принимает буфер, который, как я понимаю, переопределяет буфер ОС по умолчанию. Когда дейтаграмма получена, она подается в буфер, и процедура завершения называется, заполнен буфер или нет.

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

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

Ответы [ 7 ]

6 голосов
/ 20 мая 2009

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

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

РЕДАКТИРОВАТЬ - по сути, UDP это «запустить и забыть». В протокол не встроен механизм обратной связи, как в TCP. Единственный способ настроить скорость передачи - дать дальнему концу сказать, что он не получает весь поток. См. Также RFC 2309 .


Re: Последовательности пакетов - переупорядочение не происходит из-за физического уровня, обычно это происходит потому, что IP-сети «с коммутацией пакетов», а не «с коммутацией каналов».

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

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

3 голосов
/ 20 мая 2009

Чтобы избежать проблем с буферами ОС, вам необходимо внедрить систему контроля скорости. Это может быть замкнутый контур (получатель отправляет обратно ACK и информацию о его буферах) или разомкнутый контур (отправитель замедляется, что означает, что вы должны быть консервативны).

Существуют полустандартные протоколы для UDP для реализации обоих. На ум приходит RBUDP (Reliable Blast UDP), и есть другие.

2 голосов
/ 20 мая 2009

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

Это позволит избежать подтверждений после начального периода оценки, но будет работать только в том случае, если нагрузка на сеть / процесс приема не изменится.

Раньше я писал UDP-клиенты на Python, и единственный раз, когда я обнаружил значительную потерю пакетов, был слишком мал входной буфер в процессе приема. В результате, когда система находилась под большой нагрузкой, вы получили бы потерю пакетов, потому что буфер молча переполнялся.

1 голос
/ 21 мая 2009

Если вы передадите флаг WSA_FLAG_OVERLAPPED на WSASocket(), вы можете вызвать WSARecvFrom() несколько раз, чтобы поставить в очередь несколько запросов ввода-вывода. Таким образом, уже есть другой буфер, доступный для приема следующего пакета, даже до того, как ваша подпрограмма завершения поставит в очередь другой запрос ввода-вывода.

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

0 голосов
/ 11 февраля 2014

Похоже, что буферизация ОС не справляется с менее частыми переключениями контекста, то есть более частые переключения контекста требуются для низкоуровневых отправок. Проверьте, есть ли способ оптимизировать размер буфера отправки низкого уровня.

0 голосов
/ 20 мая 2009

Вы должны делать что-то не так. Единственный способ потерять пакеты - это 1) ненадежная сеть. 2) вы отправляете данные слишком быстро, чтобы их принимала принимающая программа. 3) Вы отправляете сообщения, размер которых превышает максимальный размер сообщения UDP. 4) Каждое устройство в вашей сети имеет максимальный размер сообщения (MTU), поэтому, возможно, вы превышаете лимит там.

В случае # 1, поскольку вы отправляете на одной машине, сеть даже не задействована, поэтому она должна быть на 100% надежной. Вы не сказали, что у вас есть две сетевые карты, поэтому я не думаю, что это проблема.

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

В случае № 3, убедитесь, что все ваши сообщения опускаются ниже этого предела.

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

Я использовал UDP во многих приложениях, и он оказался очень надежным. Используете ли вы MFC для получения сообщений? Если да, то вам необходимо внимательно прочитать документацию, поскольку в ней четко указаны некоторые проблемы, о которых вам необходимо знать, но большинство людей просто приукрашивают их. Мне пришлось исправить некоторые из этих проблем, когда люди не могли понять, почему не работает обмен сообщениями.

РЕДАКТИРОВАТЬ: Вы говорите, что ваши пакеты неявно переупорядочены. Я мог бы начать с проверки того, что ваше неявное переупорядочение действительно работает правильно. Это кажется наиболее вероятным кандидатом для вашей проблемы.

РЕДАКТИРОВАТЬ # 2: Вы пытались использовать сетевой монитор. Microsoft имеет (или, по крайней мере, раньше) бесплатную программу Network Monitor, которая, вероятно, поможет.

0 голосов
/ 20 мая 2009

Я подозреваю, что IP-уровень вашей машины не может передавать так быстро, как вы их отправили.

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

Различные результаты могут быть объяснены другими процессами трафика или процессора на вашей машине. Вы смотрели с top (unix) или prcess explorer (nt) во время ваших тестов?

...