Russian Qt Forum
Ноябрь 23, 2024, 22:29 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Modbus/TCP ошибочный пакет  (Прочитано 8563 раз)
juvf
Программист
*****
Offline Offline

Сообщений: 570


Просмотр профиля
« : Июль 15, 2009, 14:08 »

Ктонибудь реализовывал протокол Modbus/TCP? Что делать слэйву, если пакет с ошибкой?

В Modbus RTU всё понятно. Если адрес не тот, или CRC не совпал, то молчим. А если не то значение или не допустимые данные, то отвечаем исключением. А как в Modbus/TCP ?

В спецификации протокола MODBUS/TCP описан следующий формат:

Цитировать
Запрос и ответ предваряются шестью следующими байтами:
байт 0: идентификатор транзакции – копируется сервером – обычно 0
байт 1: идентификатор транзакции – копируется сервером – обычно 0
байт 2: идентификатор протокола = 0
байт 3: идентификатор протокола = 0
байт 4: поле длины (старший байт) = 0 (так как все сообщения меньше 256)
байт 5: поле длины (младший байт) = количество следующих байтов
байт 6: идентификатор устройства (раньше «адрес SLAVE»)
байт 7: код функции MODBUS
байт 8:  данные, если требуется

Существует транспорто-зависимый префикс, который в случае MODBUS/TCP включает в себя семь байт:
ref ref 00 00 00 len unit
«ref ref» – два байта «смещения транзакции» - число, которое не имеет значения на сервере, но копируется дословно от запроса к ответу для удобства клиента. Простые клиенты обычно оставляют эти значения нулевыми.

Слэйв получит пакет по TCP, в котором транспорто-зависимый префикс будет с ошибкой, например идентификатор протокола не будет равен 0, или поле длины будет равно 1234, при допустимом 255 - что делать? Разрывать соединение? или игнорировать пакет(молчать), или ответить исключением с кодом ошибки?


Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #1 : Июль 15, 2009, 16:05 »

Цитировать
А если не то значение или не допустимые данные, то отвечаем исключением. А как в Modbus/TCP ?

аналогично

см п 4.4.2.1 в MODBUS Messaging on TCP/IP Implementation Guide V1.0b



Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #2 : Июль 15, 2009, 16:14 »

вот еще:
---
Операционные системы и языки программирования, которые
поддерживают многопоточность, например JAVA, могут использовать
многопоточную стратегию, описанную здесь:
Используйте listen() для ожидания входящего соединения на TCP порт
502. Когда запроса нового соединения получен, используйте accept()
для его подтверждения и создайте новый поток для управления
соединением.
В новом потоке выполняйте следующий бесконечный цикл:
Выдайте recv(6) запрос для 6 байт MODBUS/TCP заголовка. Не
выставляйте здесь время ожидания, а ожидайте, пока запрос не
пройдет или соединение не закроется. Обе ситуации автоматически
известят поток.
Проанализируем заголовок. Если он окажется нарушенным, например,
поле протокола ненулевое или длина сообщения более 256, тогда в
одностороннем порядке закройте соединение. Это надлежащий ответ
сервера, если возникла ситуация, предполагающая неправильное TCP
кодирование.
Выдайте recv() для оставшихся байтов сообщения, длина которых
известна. Помните, что в отдельных случаях, при выдаче recv() с
подобным ограничением по длине допускает клиентов, требующих
«конвейерных» запросов. Любые подобные конвейерные запросы будут
оставаться в буферах TCP сервера или клиента, и будут обработаны
позже, когда существующие запросы завершатся.
Теперь обработайте входящее MODBUS сообщение, если необходимо,
приостановив текущий поток, пока правильный ответ не будет
подсчитан. В итоге у вас будет либо действительное MODBUS
сообщение или сообщение исключения EXCEPTION для использования в
качестве ответа.
Сформируйте MODBUS/TCP префикс для ответа, путем копирования байт
0 и 1 поля «идентификатора транзакции» запроса, и пересчитав длину
поля. Подтвердите ответ, включая MODBUS/TCP префикс, как один
буфер для передачи по соединению, используя send()
Вернитесь и ждите следующих 6 байт префикса записи.
В конечном счете, когда клиент решит закрыть соединение, команда
recv() 6 байт префикса не сработает. Правильное закрытие обычно
возвращает в команде recv() нулевое количество байт.
Принудительное закрытие может вызвать ошибочный результат команды
recv(). В любом случае, закройте соединение и существующий поток.
----
Записан

ArchLinux x86_64 / Win10 64 bit
juvf
Программист
*****
Offline Offline

Сообщений: 570


Просмотр профиля
« Ответ #3 : Июль 16, 2009, 07:03 »

Цитата: kuzulis
Проанализируем заголовок. Если он окажется нарушенным, например,
поле протокола ненулевое или длина сообщения более 256, тогда в
одностороннем порядке закройте соединение. Это надлежащий ответ
сервера, если возникла ситуация, предполагающая неправильное TCP
Это приложение спецификации OPEN MODBUS/TCP SPECIFICATION от 1999 года, в которой не оговариваются чёткие рамки, а просто предлагается некая реализация сервера. 

Однко в MODBUS Messaging on TCP/IP Implementation Guide V1.0b от 2006 года говорится
Цитировать
The MODBUS PDU Checking function consists of first parsing the MBAP Header. The Protocol Identifier field has to be checked :
       If it is different from MODBUS protocol type, the indication is simply discarded.

 is simply discarded - я это понял так  "просто бракуется (отвергается)". Т.е. если в транспорто-зависимом префиксе (заголовоке) ошибка, то соединение не разрывается, а просто эта посылка бракуется, игнорируется.

ps Но мне кажется, что разорвать соединение - это более правильно. имхо. Дилемма ((
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #4 : Июль 16, 2009, 07:51 »

Цитировать
ps Но мне кажется, что разорвать соединение - это более правильно. имхо. Дилемма ((
Ну да! Я тож считаю что так и нужно делать (разрывать), т.к PID отличный от нуля НЕ есть PID модбаса - а PID како-го то иного протокола.. а ваш сервер ведь МОДБАС! так какой ему резон поддерживать подключение - если ему шлют НЕ МОДБАС ADU ! Улыбающийся т.е. нужно рвать..

ЗЫ: Вы когда слышите уругвайское наречие - вы разве пытаетесь понять что там говорят? НЕТ! Вы просто говорите им : "пошли Вы нафик"  Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
alex12
Гость
« Ответ #5 : Июль 20, 2009, 23:39 »

Я много работал и программировал Modbus. И RTU и TCP.

Мое мнение: если пакет ошибочен -- сразу надо разрывать связь (закрывать сокет). Ошибочный пакет - значит все - что-то накрылось. Где-то произошел сбой и единственный метод разрулить эту ситуацию - закрыть сокет.

Еще интересный момент: тайм-аут. Сам TCP не отслеживает ситуацию, когда пакеты просто перестали идти. Напритер где-то накрылся канал. Открытый TCP сокет на сервере будет бесконечно ждать нового запроса, который физически уже не может прийти в данной сессии. Поэтому нужно на сервере делать тайм-аут по неактивности клиента. Со стороны клиента, кстати, тоже возможна ситуация, когда клиент послал запрос, и в этот момент линия отвалилась. Без таймаута он будет ждать ответа бесконечно.

То, что после сбоя или тайм-аута клиент заново открывает соединение совершенно нормально.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.05 секунд. Запросов: 23.