Gymterview
junior

Что такое трёхстороннее рукопожатие (three-way handshake)?

Three-way handshake — процедура установления TCP-соединения между клиентом и сервером, состоящая из обмена тремя сегментами (SYN → SYN-ACK → ACK), в ходе которого обе стороны согласовывают начальные номера последовательностей и подтверждают готовность к передаче данных.

Аналогия из жизни: это как телефонный звонок. Вы звоните и говорите «Алло?» (SYN). Собеседник отвечает «Алло, слышу вас!» (SYN-ACK). Вы подтверждаете «Отлично, и я вас слышу, давайте поговорим» (ACK). Только после этого начинается разговор.

Схема установления соединения

Пример
Клиент                              Сервер
   |                                   |
   |-------- SYN (seq=x) ------------>|  1. Клиент хочет соединиться
   |           Состояние: SYN_SENT     |     Состояние: LISTEN
   |                                   |
   |<--- SYN-ACK (seq=y, ack=x+1) ---|  2. Сервер подтверждает и предлагает свой номер
   |           Состояние: SYN_SENT     |     Состояние: SYN_RECEIVED
   |                                   |
   |-------- ACK (ack=y+1) ---------->|  3. Клиент подтверждает
   |           Состояние: ESTABLISHED  |     Состояние: ESTABLISHED
   |                                   |
   |       Соединение установлено      |

Детальное описание шагов

Шаг 1 — SYN (Synchronize):

  • Клиент отправляет сегмент с флагом SYN и начальным номером последовательности (seq=x, где x — случайное число, ISN — Initial Sequence Number)
  • Клиент переходит в состояние SYN_SENT
  • ISN генерируется случайно для защиты от атак подмены (TCP sequence prediction)

Шаг 2 — SYN-ACK:

  • Сервер получает SYN, отвечает сегментом с флагами SYN и ACK
  • seq=y (свой начальный номер), ack=x+1 (подтверждает получение SYN клиента)
  • Сервер переходит в состояние SYN_RECEIVED

Шаг 3 — ACK:

  • Клиент отправляет ACK с ack=y+1 (подтверждает получение SYN сервера)
  • Оба переходят в состояние ESTABLISHED — соединение установлено, можно передавать данные
  • Начиная с этого сегмента, клиент уже может отправлять данные

Зачем три шага, а не два?

  • Оба участника должны согласовать начальные номера последовательностей (ISN) для каждого направления — это требует по одному сообщению в каждую сторону плюс подтверждение
  • Два шага не гарантируют, что обе стороны готовы к передаче данных
  • Защита от дублированных SYN-пакетов от прошлых соединений (stale segments)

Завершение TCP-соединения (four-way handshake)

Пример
Клиент                              Сервер
   |-------- FIN ------------------>|  1. Клиент хочет завершить (FIN_WAIT_1)
   |<-------- ACK -----------------|  2. Сервер подтверждает (CLOSE_WAIT)
   |                                |     Клиент: FIN_WAIT_2
   |<-------- FIN -----------------|  3. Сервер тоже завершает (LAST_ACK)
   |-------- ACK ------------------>|  4. Клиент подтверждает (TIME_WAIT)
   |                                |     Сервер: CLOSED
   |  (ждёт 2×MSL ≈ 60 с)          |
   |  Состояние: CLOSED             |

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

Состояние Описание
LISTEN Сервер ожидает входящих соединений
SYN_SENT Клиент отправил SYN, ожидает SYN-ACK
SYN_RECEIVED Сервер получил SYN, отправил SYN-ACK
ESTABLISHED Соединение установлено, передача данных
FIN_WAIT_1 Отправлен FIN, ожидание ACK
FIN_WAIT_2 Получен ACK на FIN, ожидание FIN от другой стороны
CLOSE_WAIT Получен FIN, ожидание закрытия от приложения
TIME_WAIT Ожидание гарантии доставки последнего ACK (2×MSL)
CLOSED Соединение закрыто

Для Java-разработчика

  • new Socket("host", port) — внутри происходит three-way handshake
  • socket.close() — инициирует four-way handshake
  • При большом количестве короткоживущих соединений состояния TIME_WAIT могут исчерпать ресурсы (порты, файловые дескрипторы). Решение: HTTP keep-alive, connection pooling (HikariCP для JDBC)
  • ServerSocket с параметром backlog управляет очередью входящих соединений в состоянии SYN_RECEIVED

Вывод

Three-way handshake — обязательный этап установления каждого TCP-соединения. Он гарантирует, что обе стороны готовы к обмену данными и согласовали параметры. Завершение соединения — четырёхэтапное, потому что каждая сторона может иметь данные для отправки.

На собеседовании: уверенно нарисуйте диаграмму SYN → SYN-ACK → ACK. Часто спрашивают, зачем нужен TIME_WAIT (чтобы последний ACK гарантированно дошёл и чтобы stale-пакеты от старого соединения не попали в новое). Также стоит упомянуть SYN flood-атаку — злоумышленник отправляет множество SYN, не завершая handshake, и исчерпывает ресурсы сервера (защита — SYN cookies).