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 остаётся как подстраховка.
Источники
- 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)
- 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 (число зондов до таймаута)
Нашли ошибку? ·
Смотрите также
- TCPНадёжный поток байтов поверх IP: рукопожатие, порты, подтверждения, keep-alive
- MQTTПротокол издатель — подписчик через брокер: топики, QoS, retain, Last Will
- Алгоритм НейглаПравило TCP против мелких пакетов: новый сегмент ждёт подтверждения предыдущего; отключается опцией TCP_NODELAY
- Тройное рукопожатие TCPОбмен SYN, SYN-ACK, ACK при открытии соединения TCP: синхронизация начальных номеров, состояния, защита от старых дубликатов
- Окно приёма TCPПоле Window, управление потоком, нулевое окно и зонды, масштабирование окна, TCP_WND в lwIP
- NAT (трансляция адресов)Подмена адресов и портов на границе частной сети: привязки, направление сеанса, таймауты, что не работает
- ESP32ESP32, S2, S3, C2, C3, C5, C6, H2, P4: ядра, радио, USB, GPIO — сравнение и выбор