$ sudo teach IT
Модуль 5

TCP — надёжная доставка

Протокол, который превращает ненадёжную сеть в аккуратный поток данных: всё дойдёт, ничего не потеряется и не перепутается.

Вы узнаете
  • как TCP устанавливает и закрывает соединение;
  • за счёт чего он обнаруживает потери и восстанавливает порядок;
  • как он подстраивает скорость под получателя и под сеть и чем отличается от UDP.

5.1Что обещает TCP

TCP (Transmission Control Protocol) работает поверх того же ненадёжного IP, но даёт программе совсем другие условия:

  • Гарантия доставки. Каждый отправленный байт должен быть подтверждён. Нет подтверждения — данные отправляются заново.
  • Правильный порядок. Получатель расставляет пришедшие части по номерам, даже если они пришли вперемешку.
  • Без дубликатов. Пришедшее дважды отбрасывается.
  • Управление потоком. Отправитель не шлёт больше, чем получатель готов принять.
  • Управление перегрузкой. Отправитель снижает темп, если сеть не справляется.

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

Аналогия: заказное письмо с уведомлением

Вы отправляете многотомную рукопись частями. Каждая бандероль пронумерована, получатель расписывается за каждую, а если расписка не пришла — вы высылаете копию. На другом конце тома расставляют по номерам. Это дольше обычной открытки, зато рукопись дойдёт целиком.

5.2Установление соединения: тройное рукопожатие

Прежде чем передавать данные, стороны должны договориться. TCP делает это за три шага — отсюда название трёхстороннее рукопожатие (three-way handshake):

Направление Сегмент Смысл
Клиент → Сервер SYN «Хочу соединиться. Мой начальный номер — 1000»
Сервер → Клиент SYN + ACK «Согласен. Мой начальный номер — 5000, жду от тебя 1001»
Клиент → Сервер ACK «Принял. Жду от тебя 5001»

После этого соединение установлено, и можно передавать данные.

Зачем три шага, а не один? Каждая сторона должна убедиться в двух вещах: что собеседник её слышит и что она слышит собеседника. Заодно стороны обмениваются начальными номерами последовательности — они выбираются случайно, чтобы посторонний не мог подделать сегмент чужого соединения.

Рукопожатие стоит времени: один обмен «туда-обратно» (его обозначают RTT) ещё до первого байта полезных данных. На расстоянии в полмира это 150–300 миллисекунд — одна из причин, по которой появились более быстрые протоколы вроде QUIC.

5.3Номера, подтверждения и повторная отправка

Вся надёжность TCP держится на двух числах в каждом сегменте:

  • Номер последовательности (SEQ) — порядковый номер первого байта в этом сегменте.
  • Номер подтверждения (ACK) — «я получил всё до этого места, жду байт с таким-то номером».

Подтверждения накопительные: ACK 3001 означает, что получены все байты до 3000 включительно. Если какой-то сегмент пропал, получатель продолжает повторять один и тот же номер — так отправитель узнаёт, где образовалась дыра.

Механизм Как работает
Повтор по таймеру Отправитель ждёт подтверждения ограниченное время. Не дождался — отправляет сегмент заново. Время ожидания подстраивается под реальную задержку в сети.
Быстрый повтор Три одинаковых подтверждения подряд — верный признак потери. Отправитель повторяет сегмент сразу, не дожидаясь таймера.
Выборочные подтверждения (SACK) Получатель сообщает не только «жду с 3001», но и «при этом у меня уже есть 4001–6000». Отправитель повторяет только потерянный кусок.

5.4Управление скоростью: окно и перегрузка

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

Управление потоком — не перегрузить получателя

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

Управление перегрузкой — не перегрузить сеть

Сеть о своей загрузке напрямую не сообщает, поэтому TCP нащупывает допустимую скорость сам:

1. Медленный старт. Соединение начинает с небольшого объёма и удваивает его после каждого

успешного обмена — скорость растёт очень быстро.

2. Предотвращение перегрузки. После определённого порога рост становится плавным и

осторожным.

3. Реакция на потерю. Потерянный пакет считается сигналом перегрузки: скорость резко

снижается, и подбор начинается заново.

Конкретные правила называются алгоритмами управления перегрузкой. Самые распространённые сегодня — CUBIC (используется по умолчанию в большинстве систем) и BBR, который ориентируется не на потери, а на измеренную пропускную способность и задержку.

Почему это важно всем

Управление перегрузкой — причина, по которой интернет не «падает» под нагрузкой. Миллиарды соединений добровольно притормаживают, когда каналу тяжело, и делят его между собой более-менее честно.

5.5Заголовок TCP и флаги

Заголовок TCP занимает от 20 до 60 байт. Кроме портов, номеров и окна, в нём есть набор однобитных флагов, которые задают смысл сегмента:

Флаг Значение
SYN Запрос на установление соединения. Встречается только в рукопожатии.
ACK Сегмент содержит подтверждение. Установлен почти во всех сегментах, кроме самого первого.
FIN «Я закончил передачу» — вежливое завершение соединения.
RST Немедленный разрыв: порт закрыт, соединение не существует или произошла ошибка.
PSH Просьба сразу передать данные программе, не накапливая в буфере.
URG Пометка срочных данных. Сегодня почти не используется.

В рукопожатии стороны также согласуют дополнительные опции: максимальный размер сегмента (MSS — обычно 1460 байт для Ethernet), масштабирование окна для быстрых каналов, поддержку SACK и метки времени.

5.6Завершение соединения

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

Направление Сегмент Смысл
Клиент → Сервер FIN «Я всё передал»
Сервер → Клиент ACK «Понял» (сервер ещё может досылать свои данные)
Сервер → Клиент FIN «Я тоже закончил»
Клиент → Сервер ACK «Понял, закрываем»

После этого сторона, закрывшая соединение первой, ещё некоторое время помнит о нём (состояние TIME_WAIT), чтобы запоздавшие сегменты не попали в новое соединение с теми же портами.

Существует и аварийный способ — сегмент с флагом RST. Он обрывает соединение мгновенно и без подтверждений. Именно RST вы получаете в ответ, когда пытаетесь подключиться к порту, который никто не слушает: «соединение отклонено».

5.7TCP против UDP

Свойство TCP UDP
Соединение Устанавливается рукопожатием Не нужно
Доставка Гарантируется, потери повторяются Не гарантируется
Порядок данных Сохраняется Не сохраняется
Что видит программа Непрерывный поток байтов Отдельные сообщения
Управление скоростью Есть: поток и перегрузка Нет
Заголовок 20–60 байт 8 байт
Задержка перед отправкой Один обмен на рукопожатие Нет
Типичные применения Сайты, почта, файлы, удалённый доступ DNS, звонки, игры, стриминг, QUIC
Обратная сторона порядка

Раз TCP отдаёт данные строго по порядку, один потерянный сегмент задерживает всё, что пришло после него, — пока не дойдёт повтор. Это называется блокировкой начала очереди (head-of-line blocking). Для загрузки файла это не страшно, а для страницы из сотни независимых картинок — обидно. Запомните этот термин: он объяснит, зачем понадобился HTTP/3.

Вывод модуля
  • Не существует «лучшего» транспорта. TCP выбирают, когда важно получить всё и без ошибок; UDP — когда важнее скорость и свежесть данных, либо когда приложение хочет управлять надёжностью самостоятельно.
На следующий урок