Блог

Modbus TCP для интегратора: Unit ID, транзакции, таймауты и диагностика

Modbus TCP выглядит проще, чем он есть: один порт, понятные функции чтения-записи, везде одинаковый заголовок MBAP. На объекте же типичная картина - «сессия есть, а регистры то приходят, то нет», «Unit ID меняли - заработало», «таймаут увеличили - перестало падать», при этом Wireshark показывает зелёные ACK и виноватых не находят.
Эта статья - про то, как устроен обмен поверх TCP, где живёт Unit ID, как не утонуть в таймаутах и очередях опроса, и как быстро отличить проблему сети от проблемы шлюза или прошивки устройства.

Короткий ответ

Modbus TCP - это запрос-ответ внутри (обычно) одной долгоживущей TCP-сессии: каждый кадр Modbus несёт в MBAP поле Transaction ID (связка «запрос-ответ»), Protocol ID (для Modbus всегда 0), Length и Unit ID (маршрутизация к «виртуальному» устройству за шлюзом).
Таймауты нужно разделять на установление TCP, ожидание первого байта ответа, полный ответ и внутренние таймауты устройства - они независимы и дают разные симптомы.
Полураспределённые (сквозные, но не локализуемые в одной точке) сбои чаще всего связаны с NAT и таймаутами простоя TCP, буферами шлюзов, перегрузкой опроса и неверным Unit ID на границе RTU/TCP.

TCP-сессия и модель «запрос-ответ»

В отличие от классического Modbus RTU, где кадр - это пауза и байты на шине, в Modbus TCP транспорт - байтовый поток TCP. Семантика Modbus не меняется: один запрос, один ответ (кроме явно документированных особых случаев на стороне производителя).
Практически значимые варианты на объекте:
Одна TCP-сессия на устройство (или шлюз) и серия запросов-ответов подряд - самый частый режим SCADA/мастера.
Новая TCP-сессия на каждый цикл опроса - встречается у простых утилит и иногда у прошивок; даёт накладные расходы и удар по коммутаторам при большом числе узлов.
Несколько параллельных сессий к одному TCP-серверу Modbus - поддерживается не всегда; на слабом устройстве приводит к отказам, «рваным» ответам и нарушению порядка обработки.
Важно зафиксировать в документации проекта: кто открывает сессию, держит ли её постоянно, допускается ли параллельный опрос одного IP с двух клиентов (частый источник гонок).

Transaction ID, длина и целостность кадра

В MBAP поле Length задаёт число байт после себя до конца Modbus PDU (включая Unit ID и PDU). Клиент обязан сопоставлять ответ Transaction ID с ожидаемым запросом.
Типичные ошибки интеграции:
Сброс или нехранение Transaction ID при реализации собственного клиента - ответы «прилипают» не к тем запросам при асинхронном вводе-выводе.
Чтение «склейки» двух ответов из сокета без разбора по Length - особенно при буферизации на шлюзе.
Обрыв TCP посередине кадра - следующий recv даёт мусор до следующего синхронного сброса буфера на клиенте.
Диагностика: один захват tcpdump/Wireshark на участке клиент-устройство и проверка, что каждый ответ начинается с корректного MBAP и Length согласован с фактическим размером.

Unit ID и шлюзы

Unit ID в MBAP - это не «адрес Ethernet», а логический адрес подчинённого на стороне Modbus. На «чистом» TCP-устройстве с одним контроллером внутри часто везде Unit ID = 255 или 1 - зависит от вендора, но главное - единообразие.
За шлюзом RTU→TCP или мультипорторым концентратором один IP:502 может обслуживать несколько RTU-адресов: Unit ID в TCP-кадре мапится на адрес на шине RS-485.
Практические правила:
•Явно спросить в мануале: игнорирует ли устройство Unit ID, подставляет ли шлюз Unit ID сам, должен ли клиент всегда слать 0 или 255.
•При «плавающих» ответах с шлюза проверить таймауты конвертера и размер очереди - шлюз может отвечать исключением или пустым ответом, если RTU-сторона не успела.

Таймауты: клиент, ОС, сеть, устройство

Разделите хотя бы четыре уровня:
Уровень
Что настраивается
Типичный симптом при ошибке
TCP connect
Таймаут установления соединения
«Нет связи» при недоступности IP/ACL
Ответ Modbus (прикладной)
Таймаут ожидания полного кадра ответа
Таймауты при медленной логике ПЛК
TCP idle / NAT
Таймаут простоя сессии на файрволе
Работало после перезапуска, «ночью отваливается»
Устройство (внутренний)
Обработка запроса, доступ к шине за CPU
Частичные ответы, Modbus exception
Увеличение таймаута маскирует проблему, но не лечит перегрузку: если опрос слишком плотный, растёт очередь и задержка ответа, вплоть до лавины таймаутов на клиенте.

Keep-alive и «полусухие» TCP-сессии

TCP keepalive (сокетные опции ОС) помогает обнаружить мёртвую сторону после обрыва без FIN. На пути часто стоят файрволы, которые разрывают давно простаивающие сессии быстрее, чем дефолтные keepalive на ОС.
Практика:
•Для постоянных сессий задать разумный application heartbeat (редкий легитимный запрос, например чтение одного регистра статуса) короче, чем idle-timeout на межсетевом экране.
•После ночного простоя первый запрос падает - классика NAT/Firewall timeout; лечится переоткрытием сессии или keepalive, а не только Modbus-таймаутом.

Очереди опроса и джиттер

Очередь опроса - это порядок и частота запросов к разным регистрам и устройствам. Плохая дисциплина даёт:
джиттер задержки ответа (устройство не успевает между запросами);
блокировку низкоприоритетных чтений «тяжёлыми» блоками;
•на шлюзах - переполнение буфера и потерю кадров RTU.
Рекомендации:
•Группировать соседние регистры в один запрос (где позволяет карта и функция).
•Не опрашивать одно и то же из пяти разных задач без синхронизации.
•Для критичных сигналов - отдельный цикл или приоритет в драйвере SCADA, если платформа позволяет.

Полураспределённые ошибки

Назовём так ситуацию, когда ни один слой не показывает явный отказ, а симптом плавает:
•ping стабилен, Modbus периодически таймаутит;
Wireshark на клиенте чистый, а за маршрутизатором - нет;
•после перезагрузки только шлюза проблема исчезает на часы.
Имеет смысл смотреть связку очередь + NAT + прошивка + многопоточность клиента, а не искать «один сломанный провод».

Таблица: симптом - вероятная причина - что проверить первым

Симптом
Вероятная причина
Что проверить первым
Таймауты только после простоя
Idle-timeout TCP на FW/NAT
Таймауты сессий на межсетевом экране, keepalive, переоткрытие сокета
«Сессия есть», данные не сходятся
Неверный Unit ID за шлюзом
Документация шлюза, тест с разными Unit ID, захват на RS-485 стороне шлюза
Ответы «перепутаны»
Неверная обработка Transaction ID / асинхронный парсер
Логирование TID в клиенте, один поток на сокет
Стабильно на коротких запросах, падает на длинных
Лимит PDU, фрагментация, баг буфера
Уменьшить количество регистров за запрос, сравнить с лимитом вендора
Ухудшение при росте числа тегов
Перегруз опроса или устройства
Период опроса, объединение регистров, параллельные сессии к одному IP
Modbus exception 04 и подобные
Устройство не успевает (внутренняя шина, задача CPU)
Разгрузить опрос, проверить цикл ПЛК, тяжёлые функции на стороне слейва
Работает с одной SCADA, ломается с двумя
Два мастера на один слейв
Запрет второго клиента, мультиплексор, смена архитектуры
После замены коммутатора «странный» Modbus
Storm, неправильный VLAN/ACL, jumbo/старый SFP
Порт счётчики ошибок, broadcast, зеркало порта, сравнение конфигурации

Где уместен СТАБУР

В проектах на базе СТАБУР имеет смысл зафиксировать внутренний стандарт интеграции Modbus TCP: единые правила Unit ID за шлюзами, таймауты, запрет параллельного опроса одного узла без согласования и шаблон диагностики (захват + чек-лист). Это снижает стоимость сопровождения и ускоряет передачу объекта между интеграторами.

Заключение

Modbus TCP прощает многое на этапе прототипа, но не прощает смешения уровней: TCP, MBAP, политика опроса и поведение шлюза должны быть явно спроектированы. Разнесите таймауты по смыслу, контролируйте Transaction ID и Unit ID, держите опрос под нагрузкой измеримым - и большая часть «магических» отказов исчезнет без замены оборудования.

FAQ

Нужен ли отдельный Unit ID, если на IP одно устройство?

Иногда нет, но шлюзы и некоторые CPU требуют конкретного значения. Ориентируйтесь на паспорт устройства, а не на привычку.

Почему нельзя бесконечно уменьшать период опроса?

Потому что растёт время ответа и вероятность коллизий на внутренней шине устройства или на RS-485 за конвертером.

Достаточно ли Wireshark на ноутбуке?

Часто да, если точка захвата близка к проблеме. Для сквозных сбоев нужны два коррелированных захвата или зеркало порта.

Влияет ли Nagle на Modbus TCP?

В редких реализациях - да; при странных задержках пробуют TCP_NODELAY на клиенте (осознанно, с замером).

Один порт 502 - всегда ли Modbus?

На практике почти да для стандартного сервера, но политика безопасности может менять порт - проверяйте конфигурацию устройства.

Внутренняя перелинковка

Обсуждение