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

Keep-alive TCP

Соединение TCP, по которому давно ничего не передавали, с точки зрения стека живо вечно: нет данных — нет и причины что-то проверять. Если партнёр обесточен или сменился адрес, устройство узнает об этом только при следующей попытке отправки. Keep-alive заставляет стек спрашивать «ты ещё здесь?» заранее.

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

Keep-alive TCP — механизм, при котором стек TCP сам отправляет зонды по соединению, в котором давно нет данных, чтобы убедиться, что партнёр ещё отвечает. RFC 9293 (разд. 3.8.4) называет соединение простаивающим (idle), когда долго нет входящих сегментов и нечего отправлять, и описывает keep-alive как необязательную возможность: реализация может её включить (MAY-5), но сама практика «не общепринята». Без keep-alive простаивающее соединение формально живёт сколько угодно, и о пропаже партнёра устройство узнаёт лишь при следующей отправке — когда истекут повторы передачи.

Что требует RFC 9293

ТребованиеПункт
Приложение может включать и выключать keep-alive для каждого соединенияMUST-24
По умолчанию выключеноMUST-25
Зонды только когда нет неподтверждённых данных и за интервал ничего не полученоMUST-26
Интервал настраиваемыйMUST-27
Интервал по умолчанию — не меньше двух часовMUST-28
Неответ на один зонд — ещё не разрыв: ACK без данных передаются ненадёжноMUST-29
Зонд следует слать без данных; допустим один «мусорный» октетSHLD-12, MAY-6

Сам зонд — сегмент с номером SEG.SEQ = SND.NXT − 1, то есть на единицу ниже следующего ожидаемого: партнёр отвечает на него подтверждением, как на дубликат, и ничего в поток не добавляется. Поскольку подтверждение может потеряться, разрыв фиксируют только после серии зондов без ответа.

В lwIP на ESP32

Документация ESP-IDF перечисляет поддерживаемые опции сокета lwIP: SO_KEEPALIVE на уровне SOL_SOCKET включает механизм, а на уровне IPPROTO_TCP его настраивают четыре опции.

ОпцияЕдиницаСмысл по документации ESP-IDF
TCP_KEEPALIVEмспериод keep-alive
TCP_KEEPIDLEсто же, что TCP_KEEPALIVE, но в секундах
TCP_KEEPINTVLсинтервал между зондами
TCP_KEEPCNT—число зондов до признания соединения мёртвым

Время обнаружения разрыва складывается из простоя и серии зондов: TCP_KEEPIDLE + TCP_KEEPCNT × TCP_KEEPINTVL. При 60 с, 3 и 10 с это 90 с (наш расчёт); два часа по умолчанию из RFC для устройства на ESP32 с батарейным питанием и NAT на пути обычно слишком долго, а секунды — слишком часто для радиоканала, поэтому значения выбирают под задачу.

С чем не путать

  • Keep alive MQTT — механизм уровня приложения: клиент MQTT сам договаривается с брокером об интервале и шлёт служебные пакеты. Он проверяет, что живо приложение, а не только стек, и для прошивок важнее.
  • Алгоритм Нейгла — другая настройка того же сокета, о задержке мелких сегментов, к живости соединения отношения не имеет.
  • Повторные передачи — реагируют только на отправленные данные; keep-alive нужен именно потому, что при простое отправлять нечего. Установление соединения описано в термине «Тройное рукопожатие», управление потоком — в «Окно приёма TCP».

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

Почему keep-alive TCP по умолчанию выключен и такой редкий?

Так требует RFC 9293 (разд. 3.8.4): keep-alive обязан быть выключен по умолчанию (MUST-25), а интервал простоя до первого зонда — настраиваемый и по умолчанию не меньше двух часов (MUST-28). Сам стандарт лишь отмечает, что практика keep-alive «не общепринята»; причина, по сути, в том, что простаивающее соединение TCP ничего не стоит, а зонды — это трафик и лишний повод разорвать связь при кратковременной потере пакетов (наше пояснение).

Как включить keep-alive на ESP32?

В lwIP, по документации ESP-IDF, сначала SO_KEEPALIVE на уровне SOL_SOCKET, затем на уровне IPPROTO_TCP: TCP_KEEPIDLE — простой до первого зонда в секундах (TCP_KEEPALIVE — то же в миллисекундах), TCP_KEEPINTVL — интервал между зондами в секундах, TCP_KEEPCNT — сколько зондов без ответа считать разрывом. При 60, 10 и 3 соединение будет признано мёртвым через 60 + 3 × 10 = 90 с после последнего пакета (наш расчёт).

Чем keep-alive TCP отличается от keep alive в MQTT?

Уровнем. Keep-alive TCP — зонды самого стека, невидимые приложению; их ответ подтверждает только, что стек партнёра жив, но не что приложение на нём работает. Keep alive MQTT — часть протокола MQTT: клиент договаривается с брокером об интервале и сам шлёт служебные пакеты, а брокер закрывает соединение, если клиент замолчал. Второй механизм проверяет приложение, и в прошивке обычно нужен именно он; keep-alive TCP остаётся как подстраховка.

Источники

  1. IETF. W. Eddy (ed.). Transmission Control Protocol (TCP). RFC 9293, STD 7, August 2022 — разд. 3.8.4: соединение «простаивает», если долго нет входящих сегментов и нет новых или неподтверждённых данных; keep-alive — необязательная возможность (MAY-5), практика не общепринята; зонд обычно содержит SEG.SEQ = SND.NXT − 1 и может нести один «мусорный» октет; приложение должно иметь возможность включать и выключать keep-alive для каждого соединения (MUST-24), по умолчанию выключено (MUST-25); зонды только при отсутствии неподтверждённых данных и если за интервал ничего не получено (MUST-26); интервал настраиваемый (MUST-27), по умолчанию не меньше двух часов (MUST-28); отсутствие ответа на конкретный зонд нельзя считать разрывом, так как ACK без данных передаются ненадёжно (MUST-29); зонд следует слать без данных (SHLD-12), допустим один мусорный октет для совместимости с ошибочными реализациями (MAY-6)
  2. Espressif. ESP-IDF Programming Guide v6.1, ESP32: lwIP — разд. Socket Options: на уровне SOL_SOCKET поддерживается SO_KEEPALIVE; на уровне IPPROTO_TCP — TCP_KEEPALIVE (период keep-alive в миллисекундах), TCP_KEEPIDLE (то же в секундах), TCP_KEEPINTVL (интервал между зондами в секундах), TCP_KEEPCNT (число зондов до таймаута)
Страница помогла?

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