Webrium
Подписаться

Чем TCP отличается от UDP и что из этого следует

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

Схема стыка: совпадение гарантий TCP и разрыв данных UDPНадёжность TCPПотери UDP

TCP и UDP: как работают и почему ломаются по-разному

Когда речь заходит о сетевых протоколах, чаще всего вспоминают TCP и UDP. Оба работают поверх IP, оба используют порты для адресации приложений, но на этом их сходство заканчивается. TCP - это соединение и надёжный упорядоченный поток байтов, где каждый байт нумеруется, подтверждается, а порядок восстанавливается до передачи приложению. UDP - это отдельные датаграммы без соединения и гарантий: каждая отправка - самостоятельное сообщение, которое может потеряться, прийти дважды или обогнать предыдущее.

Пространства портов у них раздельные: один и тот же номер может одновременно использоваться TCP-сокетом и UDP-сокетом, и это будут разные сокеты. Соединение TCP определяется уникальной четвёркой: два IP-адреса и два порта. Поэтому сервер может обслуживать множество клиентов через один порт - каждое новое соединение создаёт новый сокет, но использует тот же локальный порт.

Установление соединения: цена предварительных переговоров

Прежде чем передать первые данные, TCP должен установить соединение. Этот процесс называется трёхэтапным рукопожатием:

  1. Клиент отправляет SYN-пакет, сообщая о желании установить соединение
  2. Сервер отвечает SYN-ACK, подтверждая готовность к соединению
  3. Клиент отправляет ACK, завершая установление соединения

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

UDP не требует никаких предварительных переговоров. Датаграмму можно отправить сразу, без установления соединения. Это экономит время, но имеет свои последствия: адрес отправителя не проверяется, и служба, отвечающая на непроверенные запросы, может стать инструментом для атак.

Надёжность против скорости: как обрабатываются данные

Надёжность TCP означает: либо байты доставлены по порядку, либо соединение завершается ошибкой; после обрыва отправитель не знает, какие из записанных байтов собеседник получил и обработал. Держится она на нумерации и подтверждениях. Каждый байт получает уникальный номер последовательности. Получатель подтверждает принятые данные, а отправитель повторно передаёт потерянные сегменты. Дубликаты отбрасываются, а порядок восстанавливается до передачи приложению.

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

TCP использует два механизма для контроля скорости передачи:

  1. Управление потоком: получатель сообщает размер доступного буфера, чтобы отправитель не переполнил его
  2. Управление перегрузкой: отправитель самостоятельно снижает скорость при признаках перегрузки сети

Для приложения оба механизма выглядят одинаково: запись блокируется или возвращает ошибку “повторите позже”.

UDP не предоставляет никаких гарантий доставки, порядка, защиты от дублей или целостности данных. Датаграмма может:

  • Потеряться по пути
  • Прийти несколько раз
  • Прийти не в том порядке
  • Быть повреждена

Контрольная сумма у UDP по умолчанию включена, и повреждённая датаграмма тогда молча отбрасывается; в IPv4 сумма необязательна, в IPv6 обязательна. Она короткая и ловит не всякое повреждение, поэтому целостность данных не обещает ни UDP, ни TCP.

Темп отправки остаётся на приложении: у UDP нет ни управления потоком, ни управления перегрузкой, и сигнала “помедленнее” отправитель не получает - кто шлёт слишком быстро, просто теряет датаграммы.

Границы сообщений: как приложение получает данные

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

Чтение, вернувшее ноль байтов в TCP, означает корректное закрытие соединения собеседником.

UDP сохраняет границы сообщений: одна отправка всегда соответствует одной датаграмме и одному чтению. Датаграмма нулевой длины - допустимое сообщение. Если буфер чтения меньше датаграммы, избыточные данные теряются. В Linux чтение возвращает усечённые данные без ошибки, но с флагом, указывающим на усечение.

Датаграмма крупнее, чем пропускает путь, либо дробится на уровне IP, либо не доходит: в IPv4 дробить может отправитель или маршрутизатор, и только если не стоит запрет фрагментации, а в IPv6 маршрутизаторы не дробят никогда - слишком большой пакет отбрасывается, и отправителю уходит ICMP-сообщение. Поэтому размер датаграммы держат в пределах «MTU пути минус заголовки IP и UDP», а своё значение считают сами: размер заголовка IP зависит от версии протокола и наличия опций.

В Linux MTU интерфейса и MTU пути до конкретного узла смотрят так:

ip link show
tracepath <узел>

Тупик: “UDP быстрее, давайте использовать его”

Когда сталкиваются с проблемами производительности, первое, что пробуют - перевести обмен на UDP. Логика кажется очевидной: нет рукопожатия, нет блокировки начала очереди, значит должно быть быстрее.

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

Как только выясняется, что данные терять нельзя, приходится реализовывать собственные механизмы:

  • Подтверждения доставки
  • Повторную отправку потерянных пакетов
  • Восстановление порядка
  • Ограничение скорости передачи

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

Что протоколы не сообщают приложению

Успешная операция записи в TCP-сокет означает только, что данные скопированы в буфер ядра. Простаивающее соединение без специальных проверок не замечает пропажи собеседника. Проверки живости (keepalive) по умолчанию отключены и включаются отдельно для каждого сокета. Системный простой до первой проверки по умолчанию измеряется часами и действует только на сокеты, где проверки включены. Остальное о проверках живости и о молчаливом обрыве простаивающего соединения — в материале Пул соединений: то их слишком много, то ни одного.

Отказ в соединении и тайм-аут при установлении TCP-соединения здесь не разбираются - о них материал Connection refused и timed out: что говорит текст ошибки; ошибка, пришедшая кодом ответа от прокси, - уровень выше транспорта, о ней 502 и 504: кто именно не ответил и что чинить.

Со стороны UDP ситуация ещё менее определённая. Молчание ничего не доказывает. Сокеты и правила фильтрации для TCP и UDP независимы - открытый TCP-порт не означает открытый UDP-порт с тем же номером. Промежуточные устройства с состоянием (трансляция адресов, межсетевой экран) ведут учёт и для UDP, но у этого протокола нет ни рукопожатия, ни закрытия, и запись на устройстве живёт только по таймеру, причём короткому. Поэтому приложение поверх UDP шлёт периодические пакеты, чтобы эта запись не истекла.

Позиция редакции

По умолчанию следует выбирать TCP. UDP оправдан в трёх случаях:

  1. Когда опоздавшие данные бесполезны и ожидание повтора хуже потери: голосовая связь, видеоконференции, быстрые сетевые игры. Для видео по запросу или трансляций с буферизацией это не подходит - там опоздавшие данные всё ещё полезны.

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

  3. Когда датаграммы отправляются на широковещательные или групповые адреса, где получатели заранее неизвестны или одна отправка адресована сразу нескольким получателям. TCP-соединение на такие адреса установить нельзя.

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

Позиция неверна, если выбирается готовый протокол поверх UDP, который сам реализует подтверждения, порядок и управление перегрузкой. В этом случае выбор UDP - это выбор конкретного протокола, а не отказ от гарантий. Также позиция неверна, когда потери на пути редки, а задержки из-за блокировки начала очереди обходятся дороже собственной реализации механизмов надёжности.

С чем это связано

Метка над заголовком говорит, зачем туда идти: продолжить тему, перейти к практике или увидеть возражение.

Письмо по вторникам

Один разбор недели и короткий список того, что изменилось. Без дайджестов на сорок ссылок.

Начните вводить — материалы появятся здесь.

↑↓ выбрать · Enter открыть · Esc закрыть