Трёхстороннее рукопожатие TCP

Трёхстороннее рукопожатие TCP

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

Зачем вообще нужно рукопожатие

Прежде чем передавать данные, TCP должен убедиться, что обе стороны живы и готовы к общению. Также на этапе рукопожатия стороны согласуют начальные порядковые номера (sequence numbers) — они выбираются случайно, чтобы старые пакеты от предыдущих соединений не были ошибочно приняты за новые.

Шаг за шагом

Клиент хочет установить соединение с сервером. Начинается танец:

Шаг 1: SYN (Synchronize). Клиент → Сервер.

Клиент отправляет TCP-сегмент с флагом SYN и случайным начальным порядковым номером SEQ = x (например, SEQ = 1000). Никаких данных в этом сегменте ещё нет — это чистый запрос на соединение.

Клиент: "Привет, я хочу общаться. Мой начальный номер: 1000."

Шаг 2: SYN-ACK (Synchronize-Acknowledgment). Сервер → Клиент.

Сервер отвечает сегментом с двумя флагами: SYN (я тоже хочу синхронизироваться) и ACK (я подтверждаю твой номер). Сервер устанавливает свой начальный порядковый номер SEQ = y (например, SEQ = 5000) и подтверждает номер клиента: ACK = x + 1 (то есть ACK = 1001).

Сервер: "Принято. Мой начальный номер: 5000. Жду от тебя байт 1001."

Шаг 3: ACK (Acknowledgment). Клиент → Сервер.

Клиент подтверждает получение SYN-сегмента сервера: ACK = y + 1 (то есть ACK = 5001). В этом сегменте уже могут быть данные.

Клиент: "Принял. Начинаем передачу данных."

Соединение установлено. Все три шага вместе занимают ровно полтора круговых времени (RTT): SYN туда, SYN-ACK обратно, ACK туда.

Клиент                              Сервер
  │─────────── SYN ────────────────→│
  │                                   │
  │←──────── SYN-ACK ──────────────│
  │                                   │
  │─────────── ACK ────────────────→│
  │                                   │
  │═══ соединение установлено ═══════│
  │         (можно слать данные)      │

Почему именно три шага, а не два

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

Третий шаг (ACK от клиента) гарантирует, что клиент действительно хотел установить это соединение, а не просто «запоздавшее эхо».

Завершение соединения: четырёхстороннее рукопожатие

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

  1. Клиент → Сервер: FIN (я закончил отправлять данные).
  2. Сервер → Клиент: ACK (я подтверждаю, что ты закончил).
  3. Сервер → Клиент: FIN (я тоже закончил).
  4. Клиент → Сервер: ACK (подтверждаю, что ты закончил).

После шага 2 клиент больше не отправляет данные, но всё ещё может их принимать — это называется полузакрытое состояние. Сервер может ещё какое-то время допередать оставшиеся данные и только потом послать свой FIN.

Состояния TCP-соединения

TCP-соединение проходит через несколько состояний. Самые важные:

  • LISTEN — сервер ждёт входящих соединений.
  • SYN-SENT — клиент отправил SYN, ждёт SYN-ACK.
  • SYN-RECEIVED — сервер получил SYN, отправил SYN-ACK, ждёт ACK.
  • ESTABLISHED — соединение установлено, идёт передача данных.
  • FIN-WAIT — одна сторона инициировала закрытие, ждёт FIN от другой.
  • TIME-WAIT — соединение закрыто, но порт удерживается ещё ~2 минуты, чтобы гарантировать, что запоздавшие пакеты не будут приняты за новое соединение.

Состояние TIME-WAIT — частая причина ошибки «Address already in use» при перезапуске серверов: порт ещё не освободился после предыдущего соединения.

Проверь себя

  1. Сколько времени занимает установка TCP-соединения?
  2. Зачем нужны случайные начальные порядковые номера?
  3. Что такое полузакрытое состояние?
<details> <summary>Ответы</summary>
  1. Полтора RTT (round-trip time). SYN + SYN-ACK = 1 RTT, ACK = 0.5 RTT (клиент может начать слать данные вместе с ACK).
  2. Чтобы старые пакеты от предыдущего соединения с теми же адресами и портами не были ошибочно приняты за данные нового соединения случайные номера делают такую путаницу практически невозможной.
  3. Это состояние после того, как одна сторона отправила FIN и получила ACK, но другая сторона ещё не отправила свой FIN. Первая сторона уже не отправляет данные, но всё ещё принимает.
</details>

Что унести с урока

  • TCP-соединение устанавливается за три шага: SYN → SYN-ACK → ACK.
  • Три шага, а не два, чтобы защититься от старых дублированных запросов.
  • Закрытие требует четырёх шагов: FIN → ACK → FIN → ACK.
  • Случайные начальные номера предотвращают пересечение старых и новых пакетов.
  • Состояние TIME-WAIT (~2 минуты) защищает от перемешивания пакетов разных соединений.

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

Попробуйте интерактивную версию

Практические задачи, квизы и AI-наставник — бесплатный старт без карты

Перейти к практике