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

TCP

Веб-сервер на ESP32, Modbus TCP и клиент MQTT начинают работу одинаково: открывают соединение TCP. Этот протокол превращает отдельные IP-пакеты в надёжный поток байтов — с подтверждениями, повторами и порядком.

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

TCP (Transmission Control Protocol) — транспортный протокол стека TCP/IP, который даёт приложению надёжный упорядоченный поток байтов между двумя узлами. Протокол IP доставляет отдельные пакеты без гарантий: они теряются, дублируются и приходят не по порядку. TCP нумерует каждый байт, подтверждает приём, повторяет потерянное и собирает поток в исходном порядке. Текущая спецификация — RFC 9293 (2022), она заменила RFC 793.

Соединение и порты

Соединение определяется парой «IP-адрес и порт» с каждой стороны; порты 16-битные. Сервер ждёт подключений на известном порту — Modbus TCP, например, на зарегистрированном порту 502, — а клиент открывает соединение из временного порта. Устанавливается оно тройным рукопожатием:

  1. клиент → сервер: SYN со своим начальным номером последовательности;
  2. сервер → клиент: SYN и ACK со своим номером и подтверждением;
  3. клиент → сервер: ACK.

Начальный номер 32-битный и выбирается заново для каждого соединения. Закрытое соединение ещё 2 MSL держится в состоянии TIME-WAIT; RFC 9293 принимает MSL равным 2 минутам, так что у стороны, закрывшей соединение первой, ресурсы освобождаются не сразу.

Заголовок и размер сегмента

Заголовок содержит порты, номер последовательности и номер подтверждения (по 32 бита), окно приёма (16 бит), флаги и контрольную сумму. Его длина задаётся полем Data Offset в 32-битных словах; без опций это пять слов, то есть 20 байт (наш пересчёт). Если сторона не прислала опцию MSS, отправитель обязан считать максимальный сегмент равным 536 байт для IPv4 и 1220 для IPv6.

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

Стек TCP/IP занимает память под буферы каждого соединения, поэтому их число ограничено: у W5500 восемь аппаратных сокетов, у программного стека на МК — сколько хватит ОЗУ (подробнее — в статье «Ethernet для микроконтроллеров»). Две частые проблемы:

  • Мёртвые соединения. По простаивающему соединению TCP ничего не шлёт и об обрыве кабеля не узнает. Keep-alive по RFC 9293 по умолчанию выключен, а интервал по умолчанию — не меньше двух часов. Руководство Modbus рекомендует включать KEEPALIVE на обеих сторонах; надёжнее дополнить его таймером тишины в приложении.
  • Поток вместо сообщений. TCP не сохраняет границы записей: два вызова send могут прийти одним куском, один — двумя. Поэтому протоколы поверх TCP сами отмечают длину сообщения — в Modbus TCP это поле длины заголовка MBAP вместе с идентификатором транзакции.

Собрать и разобрать кадр Modbus TCP поможет калькулятор Modbus TCP. Когда надёжность не нужна или важнее задержка, вместо TCP используют UDP; когда нужна защита канала, поверх TCP запускают TLS.

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

Что такое тройное рукопожатие TCP?

Установление соединения тремя сегментами: клиент шлёт SYN со своим начальным номером последовательности, сервер отвечает SYN и ACK со своим номером и подтверждением, клиент подтверждает ACK. По RFC 9293 главная причина трёх шагов — не принять за новое соединение задержавшийся в сети старый SYN. Только после этого стороны передают данные.

Почему соединение Modbus TCP «висит» после обрыва кабеля?

TCP сам ничего не отправляет по простаивающему соединению, поэтому сторона, которая молчит, не узнает об обрыве. Keep-alive по RFC 9293 по умолчанию выключен, а если включён, интервал по умолчанию не меньше двух часов. Руководство Modbus советует включать KEEPALIVE на обеих сторонах или следить за тишиной таймерами приложения и закрывать соединение самому.

Чем TCP отличается от UDP?

TCP устанавливает соединение, нумерует байты, подтверждает приём, повторяет потерянное и отдаёт данные приложению по порядку. UDP шлёт отдельные датаграммы с заголовком 8 байт без соединения и гарантий доставки. TCP нужен для HTTP, MQTT и Modbus TCP, UDP — для DHCP, DNS и потоков, где опоздавший пакет уже не нужен.

Источники

  1. IETF. RFC 9293 Transmission Control Protocol (TCP), STD 7 (August 2022) — разд. 3.1: поля заголовка — порты отправителя и получателя по 16 бит, номер последовательности и номер подтверждения по 32 бита, Data Offset — длина заголовка в 32-битных словах, окно 16 бит; разд. 3.4.1: 32-битный начальный номер ISN; разд. 3.4.2: MSL принят равным 2 минутам; разд. 3.5: тройное рукопожатие (3WHS) SYN → SYN, ACK → ACK, его главная цель — не принять старые дубликаты начала соединения; разд. 3.6: состояние TIME-WAIT длится 2 MSL (MUST-13); разд. 3.7.1: без опции MSS отправитель обязан считать MSS равным 536 байт для IPv4 (576 − 40) и 1220 для IPv6; разд. 3.7.4: алгоритм Нейгла; разд. 3.8.4: keep-alive необязательны, по умолчанию выключены, интервал по умолчанию не меньше двух часов
  2. Modbus Organization. MODBUS Messaging on TCP/IP Implementation Guide V1.0b (October 24, 2006) — разд. 3.1.3 и 4.2.1.2: все ADU MODBUS/TCP передаются по TCP на зарегистрированный порт 502, сервер слушает порт 502; разд. 4.3.2: по умолчанию по простаивающему соединению TCP данные не идут, рекомендуется включать KEEPALIVE на клиенте и сервере, но короткий таймер тратит полосу и рвёт исправные соединения при кратких сбоях; типичные параметры Berkeley: 75 с на установление соединения, простой 2 ч до первой пробы, далее пробы каждые 75 с, не более 8

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