Название: Modbus/TCP ошибочный пакет Отправлено: juvf от Июль 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 - что делать? Разрывать соединение? или игнорировать пакет(молчать), или ответить исключением с кодом ошибки? Название: Re: Modbus/TCP ошибочный пакет Отправлено: kuzulis от Июль 15, 2009, 16:05 Цитировать А если не то значение или не допустимые данные, то отвечаем исключением. А как в Modbus/TCP ? аналогично см п 4.4.2.1 в MODBUS Messaging on TCP/IP Implementation Guide V1.0b Название: Re: Modbus/TCP ошибочный пакет Отправлено: kuzulis от Июль 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(). В любом случае, закройте соединение и существующий поток. ---- Название: Re: Modbus/TCP ошибочный пакет Отправлено: juvf от Июль 16, 2009, 07:03 Цитата: kuzulis Проанализируем заголовок. Если он окажется нарушенным, например, Это приложение спецификации OPEN MODBUS/TCP SPECIFICATION от 1999 года, в которой не оговариваются чёткие рамки, а просто предлагается некая реализация сервера. поле протокола ненулевое или длина сообщения более 256, тогда в одностороннем порядке закройте соединение. Это надлежащий ответ сервера, если возникла ситуация, предполагающая неправильное TCP Однко в 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 Но мне кажется, что разорвать соединение - это более правильно. имхо. Дилемма (( Название: Re: Modbus/TCP ошибочный пакет Отправлено: kuzulis от Июль 16, 2009, 07:51 Цитировать ps Но мне кажется, что разорвать соединение - это более правильно. имхо. Дилемма (( Ну да! Я тож считаю что так и нужно делать (разрывать), т.к PID отличный от нуля НЕ есть PID модбаса - а PID како-го то иного протокола.. а ваш сервер ведь МОДБАС! так какой ему резон поддерживать подключение - если ему шлют НЕ МОДБАС ADU ! :) т.е. нужно рвать..ЗЫ: Вы когда слышите уругвайское наречие - вы разве пытаетесь понять что там говорят? НЕТ! Вы просто говорите им : "пошли Вы нафик" :) Название: Re: Modbus/TCP ошибочный пакет Отправлено: alex12 от Июль 20, 2009, 23:39 Я много работал и программировал Modbus. И RTU и TCP.
Мое мнение: если пакет ошибочен -- сразу надо разрывать связь (закрывать сокет). Ошибочный пакет - значит все - что-то накрылось. Где-то произошел сбой и единственный метод разрулить эту ситуацию - закрыть сокет. Еще интересный момент: тайм-аут. Сам TCP не отслеживает ситуацию, когда пакеты просто перестали идти. Напритер где-то накрылся канал. Открытый TCP сокет на сервере будет бесконечно ждать нового запроса, который физически уже не может прийти в данной сессии. Поэтому нужно на сервере делать тайм-аут по неактивности клиента. Со стороны клиента, кстати, тоже возможна ситуация, когда клиент послал запрос, и в этот момент линия отвалилась. Без таймаута он будет ждать ответа бесконечно. То, что после сбоя или тайм-аута клиент заново открывает соединение совершенно нормально. |