🔥Серия netty: самый простой встроенный кодек

Java задняя часть Netty

Это 18-й день моего участия в августовском испытании обновлений. Узнайте подробности события:Испытание августовского обновления

Введение

Причина, по которой netty мощная, заключается в том, что в нее встроено много очень полезных кодеков.Используя эти кодеки, очень удобно создавать очень мощные приложения.Сегодня я расскажу вам о самых основных встроенных кодеках в netty. .

Встроенный энкодер в netty

При знакомстве с пакетом netty мы видим, что у netty очень много артефактов, начинающихся с netty-codec, по статистике их очень много:

netty-codec
netty-codec-http
netty-codec-http2
netty-codec-memcache
netty-codec-redis
netty-codec-socks
netty-codec-stomp
netty-codec-mqtt
netty-codec-haproxy
netty-codec-dns

Всего существует 10 пакетов кодеков, из которых netty-codec является самым базовым, а остальные 9 являются расширениями и адаптациями к различным пакетам протоколов.Вы можете видеть, что netty поддерживает распространенные и популярные форматы протоколов, что является очень мощным. Поскольку содержание кодеков очень велико, объяснить их непросто.В этой статье в качестве примера будет использоваться netty-codec для объяснения самых основных и наиболее распространенных кодеков.

Проблемы, на которые следует обратить внимание при использовании кодека

Хотя netty предоставляет очень удобный кодек-кодек, как мы упоминали в предыдущей статье, некоторые кодеки необходимо использовать в сочетании с обнаружением кадров.Во-первых, используйте обнаружение кадров, чтобы разделить ByteBuf на один, представляющий реальный ByteBuf данных, затем передается на встроенный кодек netty или пользовательский кодек для обработки, чтобы добиться желаемого эффекта.

Базовый кодек, встроенный в netty

Основные кодеки в netty включают base64, bytes, сжатие, json, сортировку, protobuf, сериализацию, строку и xml.

Далее мы объясним их один за другим.

base64

Этот кодек отвечает за преобразование между ByteBuf и Base64 ByteBuf. Хотя все они от ByteBuf до ByteBuf, содержимое изменилось.

Есть два ключевых класса: Base64Encoder и Base64Decoder. Поскольку Base64Decoder — это MessageToMessageDecoder, его необходимо предварительно обработать с помощью DelimiterBasedFrameDecoder.

   ChannelPipeline pipeline = ...;
  
   // Decoders
   pipeline.addLast("frameDecoder", new DelimiterBasedFrameDecoder(80, Delimiters.nulDelimiter()));
   pipeline.addLast("base64Decoder", new Base64Decoder());
  
   // Encoder
   pipeline.addLast("base64Encoder", new Base64Encoder());

bytes

bytes предназначен для преобразования между массивом байтов и ByteBuf. Точно так же перед декодированием необходимо использовать FrameDecoder. Обычное использование выглядит следующим образом:

   ChannelPipeline pipeline = ...;
  
   // Decoders
   pipeline.addLast("frameDecoder",
                    new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));
   pipeline.addLast("bytesDecoder",
                    new ByteArrayDecoder());
  
   // Encoder
   pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
   pipeline.addLast("bytesEncoder", new ByteArrayEncoder());
   

compression

Содержимое пакета сжатия относительно богато, в основном для сервисов сжатия и распаковки данных. Поддерживаются следующие алгоритмы:

brotli
Bzip2
FastLZ
JdkZlib
Lz4
Lzf
Snappy
Zlib
Zstandard

Сжатие особенно полезно при передаче больших объемов данных за счет экономии объема передаваемых данных и увеличения скорости передачи.

Но сжатие рассчитывается по определенному алгоритму, поэтому это высокая работа ЦП, и нам нужно учитывать скорость сети и производительность ЦП при его использовании и получать от этого баланс.

json

В пакете json есть только один класс JsonObjectDecoder, который в основном отвечает за преобразование объектов JSON или массивов потоков Byte в объекты и массивы JSON.

JsonObjectDecoder является прямым подклассом ByteToMessageDecoder, поэтому ему не нужен FrameDecoder.Он определяет начальную позицию массива Byte в соответствии с совпадением скобок, тем самым различая, какие данные Byte принадлежат одному и тому же объекту Json или массиву.

Этот класс очень полезен, если мы хотим использовать JSON для передачи данных.

marshalling

Полное название Marshalling — JBoss Marshalling. Это метод сериализации объектов, созданный JBoss, но последний API JBoss Marshalling все еще на 2011-04-27. Он не обновлялся в течение 10 лет. От него отказались?

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

protobuf

Все должны быть знакомы с protobuf — форматом обмена информацией, разработанным Google, который можно рассматривать как метод сериализации. Это независимый от языка и платформы расширяемый механизм сериализации структурированных данных, похожий на XML, но меньше, быстрее и проще, чем XML.

Поддержка Protobuf в Netty заключается в возможности конвертировать сообщения и объекты MessageLite в protobuf в ByteBuf.

Два кодировщика protobuf также обеспечивают прямое преобразование сообщения в сообщение, поэтому также требуется обнаружение кадров. Конечно, вы также можете использовать другие средства обнаружения кадров, такие как LengthFieldPrepender и LengthFieldBasedFrameDecoder, следующим образом:

   ChannelPipeline pipeline = ...;
  
   // Decoders
   pipeline.addLast("frameDecoder",
                    new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));
   pipeline.addLast("protobufDecoder",
                    new ProtobufDecoder(MyMessage.getDefaultInstance()));
  
   // Encoder
   pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
   pipeline.addLast("protobufEncoder", new ProtobufEncoder());

LengthFieldPrepender автоматически добавит поле длины в начало поля:

之前:
   +----------------+
   | "HELLO, WORLD" |
   +----------------+

之后:
   +--------+----------------+
   + 0x000C | "HELLO, WORLD" |
   +--------+----------------+

Конечно, netty подготовила для protobuf два специальных обнаружения кадров, это ProtobufVarint32FrameDecoder и ProtobufVarint32LengthFieldPrepender. Прежде чем объяснять эти два класса, нам нужно понять варианты Base 128 в protobuf.

Что такое Варинты? То есть при сериализации целых чисел занимаемое пространство отличается: маленькие целые занимают меньше места, а большие целые — больше, поэтому нет необходимости фиксировать конкретную длину, что может уменьшить длину данных, но это принесет сложность разбора.

Итак, как узнать, сколько байтов требуется для этих данных? В protobuf старший бит каждого байта является битом оценки. Если этот бит установлен в 1, это означает, что следующий байт и байт вместе, указывая на одно и то же число. Если этот бит установлен в 0, это означает, что Следующий байт не имеет ничего общего с байтом, и данные заканчиваются на этом байте.

Например, байт равен 8 битам.Если он представляет целое число 1, его можно представить следующим байтом:

0000 0001

Если байт не может содержать целое число, вам необходимо использовать несколько байтов для операции подключения.Например, следующие данные представляют 300:

1010 1100 0000 0010

Почему 300? Сначала посмотрите на первый байт, его первая позиция равна 1, что указывает на то, что позади есть еще один байт. Посмотрите на второй байт, его первая позиция 0, значит, он закончился. Мы удаляем оценочный бит и превращаем его в следующее число:

010 1100 000 0010

В настоящее время значение данных не может быть вычислено, потому что в protobuf количество байтов байта перевернуто, поэтому нам нужно поменять местами два байта выше:

000 0010 010 1100 

То есть:

10 010 1100 

=256 + 32 + 8 + 4 = 300

В protobuf Varint обычно используется как длина поля, поэтому netty предоставляет ProtobufVarint32LengthFieldPrepender и ProtobufVarint32FrameDecoder для преобразования ByteBuf.

Например, добавьте длину varint в ByteBuf:

   BEFORE ENCODE (300 bytes)       AFTER ENCODE (302 bytes)
   +---------------+               +--------+---------------+
   | Protobuf Data |-------------->| Length | Protobuf Data |
   |  (300 bytes)  |               | 0xAC02 |  (300 bytes)  |
   +---------------+               +--------+---------------+

При декодировании удалите поле длины варинта:

   BEFORE DECODE (302 bytes)       AFTER DECODE (300 bytes)
   +--------+---------------+      +---------------+
   | Length | Protobuf Data |----->| Protobuf Data |
   | 0xAC02 |  (300 bytes)  |      |  (300 bytes)  |
   +--------+---------------+      +---------------+

serialization

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

Netty также предоставляет два метода преобразования объектов: ObjectDecoder и ObjectEncoder.

Следует отметить, что эти два объекта несовместимы с ObjectInputStream и ObjectOutputStream, которые поставляются с JDK.Если вы хотите быть совместимыми, вы можете использовать CompactObjectInputStream, CompactObjectOutputStream и CompatibleObjectEncoder.

string

Строка — это объект, который мы используем чаще всего, и netty предоставляет StringDecoder и StringEncoder для строки.

Точно так же перед использованием этих двух классов сообщение необходимо преобразовать, обычно используя LineBasedFrameDecoder для преобразования построчно:

   ChannelPipeline pipeline = ...;
  
   // Decoders
   pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(80));
   pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
  
   // Encoder
   pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));

xml

XML также является очень распространенным форматом, но его объем будет относительно большим, и сейчас его следует использовать меньше. netty предоставляет XmlFrameDecoder для синтаксического анализа.

Поскольку xml имеет свои собственные начальные и конечные символы, нет необходимости выполнять обнаружение фрейма, просто преобразуйте его напрямую, например:

   +-----+-----+-----------+
   | <an | Xml | Element/> |
   +-----+-----+-----------+
转换成:
   +-----------------+
   | <anXmlElement/> |
   +-----------------+
   +-----+-----+-----------+-----+----------------------------------+
   | <an | Xml | Element/> | <ro | ot><child>content</child></root> |
   +-----+-----+-----------+-----+----------------------------------+
   转换成:
   +-----------------+-------------------------------------+
   | <anXmlElement/> | <root><child>content</child></root> |
   +-----------------+-------------------------------------+

Все возможно.

Суммировать

Netty предоставляет множество отличных кодеков для адаптации к различным протоколам приложений, вы можете использовать их больше и находить различия между различными протоколами.

Эта статья была включена вwoohoo.floydpress.com/16-Netty-no…

Самая популярная интерпретация, самая глубокая галантерея, самые краткие уроки и множество трюков, о которых вы не знаете, ждут вас!

Добро пожаловать, чтобы обратить внимание на мой официальный аккаунт: «Программируйте эти вещи», разбирайтесь в технологиях, лучше поймите себя!

Категории