Перейти к содержанию

Тройное рукопожатие TCP (three-way handshake)

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

Обновлено Редакция GAW

Тройное рукопожатие (three-way handshake, 3WHS) — процедура установления соединения TCP по RFC 9293 (разд. 3.5): обмен тремя сегментами, в ходе которого обе стороны синхронизируют начальные номера последовательности и переходят в состояние ESTABLISHED. Только после него по соединению идут данные.

Три сегмента

ШагКтоСегмент (пример из RFC 9293, Figure 6)Состояние после шага
1инициатор ASYN, SEQ = 100A: SYN-SENT; B: SYN-RECEIVED
2ответчик BSYN + ACK, SEQ = 300, ACK = 101A: ESTABLISHED
3инициатор AACK, SEQ = 101, ACK = 301B: ESTABLISHED

Флаг SYN занимает один номер последовательности, поэтому подтверждение первого сегмента равно 101, а не 100. Сегмент ACK номеров не занимает — иначе, как замечает RFC, пришлось бы подтверждать подтверждения; данные в третьем сегменте уже допустимы. Ответчик до этого находился в состоянии LISTEN (пассивное открытие), инициатор вышел из CLOSED активным открытием. Стандарт обязывает поддерживать и одновременное открытие, когда обе стороны шлют SYN навстречу (MUST-10): каждая проходит CLOSED → SYN-SENT → SYN-RECEIVED → ESTABLISHED. Параметры, которыми обмениваются в SYN, — максимальный размер сегмента и масштаб окна приёма — действуют всё соединение.

Начальный номер и зачем нужен третий шаг

Каждая сторона выбирает 32-битный ISN (initial sequence number). По RFC 9293 (разд. 3.4.1) его дают «часы» — счётчик, увеличивающийся примерно каждые 4 мкс и совершающий цикл около 4,55 ч, — чтобы сегменты прежнего соединения с теми же адресами и портами не совпали по номерам с новым за время жизни сегмента MSL (2 мин). К часам рекомендовано добавлять секретную функцию от адресов и портов, не вычислимую извне: предсказуемый ISN даёт постороннему шанс подделать сегмент.

Главная причина трёх шагов, по RFC, — защита от старых дублированных SYN. Если ответчику пришёл запоздавший SYN от прежней попытки, он ответит SYN-ACK с подтверждением чужого номера; инициатор увидит неверное подтверждение и пошлёт RST, ответчик вернётся в LISTEN, а настоящий SYN обработается заново (Figure 8). Так же сбрасываются «полуоткрытые» соединения после перезагрузки одной из сторон: попытка передать данные встречает RST (разд. 3.5.1).

На микроконтроллере

Устройство за NAT всегда выступает инициатором, и первый вопрос — сколько ждать, если сервер молчит. lwIP в ESP-IDF повторяет SYN до CONFIG_LWIP_TCP_SYNMAXRTX раз (по умолчанию 12), начиная с тайм-аута CONFIG_LWIP_TCP_RTO_TIME (по умолчанию 1500 мс); меньшее число повторов быстрее даёт ошибку соединения, что удобно для перебора резервных серверов на ESP32. Время жизни сегмента CONFIG_LWIP_TCP_MSL по умолчанию 60 000 мс, а число одновременных соединений ограничено CONFIG_LWIP_MAX_ACTIVE_TCP и свободной кучей. Поверх установленного соединения дальше работают keep-alive, алгоритм Нейгла и, если нужно шифрование, собственное рукопожатие TLS — оно начинается только после третьего сегмента. Как уложить такой обмен в конечный автомат прошивки, разобрано в статье «Реализация протоколов».

Частые вопросы

Почему рукопожатие тройное, а не двойное?

Каждая сторона должна и объявить свой начальный номер последовательности, и получить подтверждение, что партнёр его принял. Первый SYN несёт номер инициатора, SYN-ACK — номер ответчика и подтверждение первого, а третий сегмент ACK подтверждает номер ответчика. RFC 9293 (разд. 3.5) называет главной причиной защиту от старых дублированных SYN: если ответчик откликнулся на запоздавший дубликат, инициатор увидит неверное подтверждение и сбросит это соединение сегментом RST, а настоящий SYN будет обработан заново.

Что такое ISN и почему он случайный?

ISN (initial sequence number) — 32-битный начальный номер, с которого сторона нумерует байты в этом соединении. По RFC 9293 (разд. 3.4.1) он берётся из «часов» — счётчика, растущего примерно каждые 4 мкс с циклом около 4,55 ч, — чтобы номера старого и нового соединения с теми же адресами и портами не совпали в пределах времени жизни сегмента. К часам добавляют секретную функцию от адресов и портов, не вычислимую извне: предсказуемый ISN позволяет постороннему вставить сегмент в чужое соединение.

Сколько ждёт ESP32, если сервер не отвечает на SYN?

lwIP в ESP-IDF повторяет SYN до CONFIG_LWIP_TCP_SYNMAXRTX раз (по умолчанию 12, диапазон 3–12), начиная с тайм-аута CONFIG_LWIP_TCP_RTO_TIME, по умолчанию 1500 мс. Для устройства, которое само инициирует соединения, это главный параметр ожидания при недоступном сервере: уменьшив число повторов, вы быстрее получите ошибку и сможете попробовать резервный адрес.

Источники

  1. IETF. RFC 9293 (STD 7) Transmission Control Protocol (TCP). W. Eddy, Ed., August 2022 — разд. 3.4.1: при открытии соединения генератор выбирает новый 32-битный ISN; «часы» ISN — 32-битный счётчик, увеличивающийся примерно каждые 4 мкс, цикл около 4,55 ч, что много больше MSL; рекомендуемая формула ISN = M + F(localip, localport, remoteip, remoteport, secretkey), F не должна быть вычислима извне (MUST-9), предсказуемые ISN — угроза безопасности; разд. 3.4.2: MSL принят равным 2 минутам; разд. 3.5: тройное рукопожатие — процедура установления соединения, Figure 6: A в SYN-SENT шлёт <SEQ=100><CTL=SYN>, B в SYN-RECEIVED отвечает <SEQ=300><ACK=101><CTL=SYN,ACK>, A переходит в ESTABLISHED и шлёт <SEQ=101><ACK=301><CTL=ACK>, после чего B в ESTABLISHED; SYN занимает один номер последовательности, ACK — нет; одновременное открытие обязано поддерживаться (MUST-10), состояния CLOSED → SYN-SENT → SYN-RECEIVED → ESTABLISHED; главная причина трёх шагов — защита от старых дублированных запросов на соединение, для чего служит сегмент RST; Figure 8: старый дубликат SYN отбрасывается через RST; разд. 3.5.1: полуоткрытые соединения сбрасываются RST при попытке передать данные
  2. Espressif. ESP-IDF Programming Guide v6.1, ESP32: Configuration Options Reference, Component config > LWIP > TCP — CONFIG_LWIP_TCP_SYNMAXRTX — максимальное число повторных передач SYN, диапазон 3–12, по умолчанию 12; CONFIG_LWIP_TCP_RTO_TIME — начальный тайм-аут повторной передачи, по умолчанию 1500 мс; CONFIG_LWIP_TCP_MSL — максимальное время жизни сегмента, по умолчанию 60 000 мс; CONFIG_LWIP_MAX_ACTIVE_TCP — максимум одновременно активных соединений TCP, практический предел определяется свободной кучей
Страница помогла?

Нашли ошибку? ·