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));
}