Возможно ли, что полученное сообщение вышло из строя или ограничено использованием Netty? - PullRequest
0 голосов
/ 28 октября 2019

Ну, я использую Java Netty Framework, для обработки сообщений по протоколу оборудования Concox, сообщения, полученные моим приложением, похоже, отличается от ожидаемого.

Полученное сообщение похоже на

EF BF BD EF BF BD EF BF BD 0D 0A 78 78 1F 12 13 0A 1C 0F 12 1D EF BF BD

И ожидаемое значение должно быть

78 78 23 12 10 03 1D 0F 17 12 C7 02 6B 6E 38 0C 39 71 00 0B 15 0E 01 CC 00 24 95 00 13 93 00 02 3D 7C 01 09 27 35 0D 0A

78 78 это стартовый бит 0D 0A это стоповый бит

Что это может быть? Мы используем эту базу приложений для большого количества протоколов, и они работают. Поддержка говорит, что это может быть проблемой с буферным соединением, но я не знаю, как это могло быть.

Я могу справиться с проблемой запускаи остановите бит в неправильном положении. Но ожидаемое сообщение все еще гораздо больше.

Ссылка на документ http://www.iconcox.in/images/tr-06-protocol.pdf

Наш код

public abstract class ExtendedObjectDecoder implements ChannelUpstreamHandler {

    @SuppressWarnings("rawtypes")
    public void handleUpstream(
            ChannelHandlerContext ctx, ChannelEvent evt) throws Exception {
        if (!(evt instanceof MessageEvent)) {
            ctx.sendUpstream(evt);
            return;
        }

        MessageEvent e = (MessageEvent) evt;
        Object originalMessage = e.getMessage();

        System.out.println((String) originalMessage);
    }
}

Pileline

@Override
    public void initTrackerServers(List<TrackerServer> serverList) {
        serverList.add(new TrackerServer(new ServerBootstrap()) {
            @Override
            protected void addSpecificHandlers(ChannelPipeline pipeline) {
                pipeline.addLast("frameDecoder", new CharacterDelimiterFrameDecoder(4096, "$", "\0"));
                pipeline.addLast("stringEncoder", new StringEncoder());
                pipeline.addLast("stringDecoder", new StringDecoder());
                pipeline.addLast("objectDecoder", new EquipProtocolDecoder(EquipProtocol.this));
            }
        });
        serverList.add(new TrackerServer(new ConnectionlessBootstrap()) {
            @Override
            protected void addSpecificHandlers(ChannelPipeline pipeline) {
                pipeline.addLast("stringEncoder", new StringEncoder());
                pipeline.addLast("stringDecoder", new StringDecoder());
                pipeline.addLast("objectDecoder", new EquipProtocolDecoder(EquipProtocol.this));
            }
        });
    }

1 Ответ

0 голосов
/ 01 ноября 2019

Netty разработан, чтобы быть упрощенным уровнем по сравнению с действующим протоколом, и, таким образом, наследует от него много семантики.

Одна важная семантика заключается в том, что TCP является протоколом на основе stream , что означает, чтокогда вы читаете какие-либо данные, вы получаете все данные по порядку, но данные могут быть распределены по нескольким пакетам, или все данные могут быть в одном пакете.

Ваш код не справляется с этим должным образом,и это вызывает ваши проблемы.

То, что произошло в вашем случае, заключается в том, что удаленная отправка 2 "пакетов, специфичных для протокола", и после чтения эти пакеты были перепутаны по "пакетам tcp"

  • До: Aaaaa Bbbbb Cccc Ddddd
  • После: Aaa aaaBbbbCccccDdddd

Вам нужно что-то, чтобы восстановить исходные сообщения снова.

На данный момент ваш конвейер существует из StringDecoder, за которым следует ваш бизнес-обработчик. К сожалению, StringDecoder не подходит для задачи обработки необработанных входящих данных и может фактически вызвать повреждение при обработке необработанных входящих данных.

К счастью для вас, "tr-06"имеет поле длины в каждом пакете. (Обнаружение наличия начального и конечного битов ненадежно, поскольку они также могут находиться внутри пакета.) Мы можем использовать это поле длины, чтобы снова декодировать «поток байтов» в «пакеты». Давайте соберем некоторую информацию и документациюпротокол:

iv. Формат пакета данных

Сообщение передается асинхронно в байтах. Общая длина пакетов составляет (10 + N) байтов

...

4.2. Длина пакета

Длина = Номер протокола + Информационное содержимое + Информация Серийный номер + Проверка ошибок, всего (5 + N)Байты, потому что информационное содержимое является полем переменной длины.

В конечном итоге мы хотим использовать решение перед сборкой для "кадрирования" байтов, поэтому давайте прочитаем документацию DelimiterBasedFrameDecoder. Мы можем видеть, что пример «поля длиной 3 байта в конце заголовка 5 байтов, не вырезать заголовок» близко соответствует тому, что нам нужно, но не совсем так. Давайте посчитаем правильные данные на основена следующих примерах:

Мы видим в примере протокола, что поле длины идет после начального бита, а начальный бит имеет длину 2 байта, поэтому смещение становится равным 2

lengthFieldOffset   = 2

СогласноСогласно документации, поле длины пакета равно 1, что означает, что оно поддерживает пакеты длиной до 255 байтов

lengthFieldLength   = 1

Это сложно вычислить, Netty предполагает, что длина пакета равна всем байтам послеполя длины содержатся в пакете, поэтому давайте посчитаем его с точки зрения netties и посмотрим, как он выстроится.

Нетти: 1 + N + 2 + 2 + 2 Протокол: 1 N + 2 + 2

lengthAdjustment    = 2

Нам нужно отрегулировать поле длины на 2

Мы не хотим удалять какие-либо байты (возможно, вы захотите включить это позже, если вас не интересуют начальные и конечные биты)

initialBytesToStrip = 0

Позволяет соединить это вместе:

        @Override
        protected void addSpecificHandlers(ChannelPipeline pipeline) {
            pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(255, 2, 1, 2, 0));
            pipeline.addLast("stringEncoder", new StringEncoder());
            pipeline.addLast("stringDecoder", new StringDecoder());
            pipeline.addLast("objectDecoder", new EquipProtocolDecoder(EquipProtocol.this));
        }
...