Первый факт:
UDP имеет 16-битное поле контрольной суммы, начинающееся с 40-го бита заголовка пакета. Это страдает от (по крайней мере) 2 слабостей:
- Контрольная сумма не является обязательной, все биты, установленные в 0, определяются как «Без контрольной суммы».
- это 16-битная контрольная сумма в строгом смысле слова, поэтому она подвержена необнаруженной порче.
Вместе это означает, что встроенная контрольная сумма UDP может быть или не быть достаточно надежной, в зависимости от вашей среды.
Второй факт:
Еще более реальной угрозой, чем повреждение данных на транспорте, является переупорядочивание потери пакетов: USP не дает никаких гарантий относительно
- все пакеты (в конечном счете) доходят до всех
- пакеты должны поступать в той же последовательности, что и отправлены
действительно, UDP вообще не имеет встроенного механизма для работы с полезной нагрузкой, превышающей один пакет, из-за того, что он не был создан для этого.
Заключение:
Добавление пакета за пакетом как полученное без дополнительных мер неизбежно приведет к получению потока приема, отличного от потока отправки во всех средах, кроме самых благоприятных, что делает этот протокол менее чем оптимальным для прямой передачи файлов.
Если вы вы хотите использовать UDP для передачи файлов, вам необходимо встроить в приложение те части, которые являются неотъемлемой частью TCP, но не UDP. Однако есть поговорка, что это, скорее всего, приведет к повторной реализации TCP.
Успешные реализации включают в себя множество одноранговых протоколов обмена файлами, в которых защита от прерывания соединения и потери или переупорядочения пакетов в любом случае должна быть частью функциональных возможностей приложения, чтобы обойти или смягчить фильтры.
Рекомендации по внедрению:
Что сработало для нас, так это реализация разбитого окна: полезная нагрузка разделена на куски фиксированной и удобной длины (мы использовали 1023 байта), массив состояния из N таких кусков хранится на отправляющей и принимающей стороне.
На стороне отправки:
- Инициируется сообщение UDP, содержащее такой фрагмент, его порядковый номер (более одного раза) в потоке и контрольную сумму или хэш.
- Массив состояния помечает этот фрагмент как «отправленный/ожидающий» с отметкой времени.
- Отправка останавливается, если используется весь массив состояния (окно отправки)
На принимающей стороне:
- полученные пакеты проверяются по контрольной сумме,
- поврежденные пакеты признаются отрицательно, если все копии порядкового номера совпадают, в противном случае отбрасываются
- Пакеты OK помечаются в массиве состояния как «полученные/ожидающие» с отметкой времени.
- Подтверждение работает путем отправки пакета подтверждения, если либо получено достаточно фрагментов для заполнения пакета подтверждения, либо временная метка самого старого «получения / ожидания» становится слишком старой (от нескольких мс до 100 мс).
- Пакеты подтверждения нуждаются в контрольной сумме, но не в последовательности.
- Чанки, для которых было отправлено подтверждение, помечаются как «подтвержденные/ожидающие» с отметкой времени в массиве состояния.
На стороне отправки:
- Пакеты подтверждения принимаются и проверяются, поврежденные пакеты отбрасываются
- Чанки, для которых было получено подтверждение, помечаются как «подтверждено/готово» в массиве статусов.
- Если первый блок в массиве состояния помечен как «подтверждено/готово», массив состояния перемещается вверх до тех пор, пока его первый блок снова не станет выполненным.
- Это может освободить один или несколько неотправленных фрагментов для отправки.
- для фрагментов со статусом «отправлено/ожидание» тайм-аут временной метки запускает новую отправку для этого фрагмента, поскольку исходный фрагмент мог быть потерян.
На принимающей стороне:
- Прием фрагмента i+N (где N — ширина окна) помечает фрагмент i как подтвержденный/готовый, перемещая окно приема вверх. Если не все фрагменты, выскальзывающие из окна приема, отмечены как «подтвержденные/ожидающие», это представляет собой неисправимую ошибку.
- для фрагментов со статусом «подтверждено/ожидание» тайм-аут временной метки запускает новое подтверждение для этого фрагмента, поскольку исходное сообщение подтверждения могло быть утеряно.
Очевидно, что есть необходимость в специальном типе сообщения от отправляющей стороны, если окно отправки выдвигается за конец файла, чтобы сигнализировать о приеме подтверждения без отправки куска N+i, мы реализовали это, просто отправив N кусков больше, чем существуют, но без полезной нагрузки.
person
Eugen Rieck
schedule
02.04.2013