
Мы уже познакомились с TCP - протоколом, который устанавливает соединение, подтверждает доставку, переотправляет потерянные данные и сохраняет порядок байтов.
Теперь посмотрим на его «младшего брата» - UDP.
UDP - это протокол, который делает всё максимально просто и быстро, но отдаёт надёжность на совесть приложения.
UDP (User Datagram Protocol) - протокол транспортного уровня, который отправляет отдельные короткие сообщения (датаграммы) без установления соединения, без подтверждений и без переотправок.
Снова напомним несколько терминов:
Транспортный уровень - это уровень в модели TCP/IP, который работает поверх IP (сетевого уровня), добавляет порты и доставляет данные конкретному приложению на устройстве.
Порт - номер сервиса на конкретном IP-адресе (аналог номера квартиры в доме).
Пакет / датаграмма (в контексте UDP можно считать синонимами) - это порция данных, которую мы передаём за один раз. У неё есть IP-адрес отправителя и получателя, порт отправителя и получателя, полезные данные.
TCP строит поверх IP надёжный поток (как провод между программами).
UDP просто отправляет отдельные сообщения - «я это послал, а дальше будь что будет».
TCP сначала устанавливает соединение (3-way handshake), ведёт состояние: «что уже отправлено», «что подтверждено», «что нужно переотправить».
UDP не устанавливает соединение, не хранит внутри себя состояние общения, каждое сообщение самостоятельное: отправили - и забыли, что с ним дальше.
В TCP есть механизм ACK (подтверждений) и таймаутов - получатель говорит: «я получил данные до такого-то номера», а если отправитель не видит подтверждения, он переотправляет сегмент.
В UDP ничего этого нет.
UDP сам по себе не проверяет дошли данные или нет, целые они или повреждённые, нужно ли что-то переотправить.
Есть два пути:
Так делают, например, некоторые протоколы для игр или передачи медиа, где нужен более гибкий контроль, чем даёт TCP.
Но ключевая мысль в том, UDP сам по себе ничего не гарантирует, кроме попытки отправить датаграмму. Всё остальное - забота приложений.
Несколько терминов, которые встанут на своё место именно с UDP:
Задержка (latency) - время от отправки пакета до его получения.
Переменная задержка (jitter) - когда задержка сильно плавает: например, один пакет пришёл через 30 мс, следующий через 80 мс, третий через 40 мс и т.д.
Потеря пакетов (packet loss) - часть пакетов просто не доходит.
В реальном времени (игры, голос, видео) небольшая задержка и потеря нескольких пакетов - терпимо, а большие задержки и сильный jitter - превращают голос в «робота», а стрим - в слайд-шоу.
UDP как раз и выбирают там, где чуть-чуть потерять лучше, чем сильно задержать.
Если UDP такой «ненадёжный», почему его вообще используют?
Потому что в ряде задач он даёт конкретные преимущества: меньше накладных расходов, ниже задержки и больше контроля у разработчика.
Разберём основные сценарии.
Примеры: онлайн-видеотрансляции, звонки по интернету, видеоконференции.
Особенности: поток идёт постоянно. Если один пакет потерялся -
его нет смысла переотправлять. Пока вы будете переотправлять старый пакет, уже пришли новые и картинка/звук уйдут далеко вперёд. Проще пропустить один кадр видео или небольшой кусок звука,
чем увидеть его через секунду задержки.
Онлайн-игры (особенно шутеры и быстрые игры). Здесь игроки постоянно пересылают координаты, действия, события. Важны низкая задержка и быстрое обновление состояния. Потеря нескольких пакетов сделает движение рывками, но игра продолжит работать.
Однако, задержка в полсекунды убивает ощущение управления и делает игру несправедливой. Поэтому многие игровые протоколы используют UDP, но поверх него реализуют свою нумерацию пакетов и выбор, что обязательно должно дойти, а что можно пропустить.
Ситуация та же, что и с видео потеря нескольких миллисекунд звука = небольшое «похрустывание», а задержка в секунду = невозможность нормально разговаривать.
VoIP-протоколы (SIP+RTP и др.) обычно используют UDP,
чтобы минимизировать задержки и не тратить время на ожидание подтверждений.
DNS-запрос - это небольшой запрос «какой IP у такого-то домена?» и небольшой ответ «IP такой-то».
Если один запрос потерялся, то клиент просто отправит его ещё раз через небольшой таймаут. Тут сложные механизмы надёжности на уровне TCP не так нужны.
Поэтому многие DNS-запросы ходят по UDP (порт 53), а в сложных случаях/при больших ответах используется TCP, но это уже более детальная история.
Пример: датчик температуры каждые 5 секунд отправляет значение на сервер, а система мониторинга отправляет метрики нагрузки.
Особенности: данные отправляются регулярно, следующее значение всё равно скоро придёт, потеря 1–2 точек не критична.
В этом случае также проще использовать UDP, а не держать множество TCP-соединений, не тратя ресурсы на подтверждения.
UDP не подходит, когда нельзя потерять данные.
Примеры: финансовые транзакции, платежи, заявки пользователей, изменения в базе.
Поэтому веб-сайты, REST API, интеграции между бизнес-системами, очереди сообщений почти всегда работают поверх TCP.