Nettyシリーズの:nettyの怠け者コードデコーダ

8285 ワード

概要


Nettyが強力なのは、非常に有用な符号化デコーダがたくさん内蔵されているためで、これらの符号化デコーダを使用することで、非常に強力なアプリケーションを簡単に構築することができます.今日はnettyの中で最も基本的な内蔵符号化デコーダについてお話しします.

Nettyに内蔵されたエンコーダ


nettyのパッケージを導入すると、nettyにはnetty-codecで始まるartifactIdがたくさんあることがわかります.統計すると、こんなにたくさんあります.
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個のcodecパッケージがあり、そのうちnetty-codecが最も基礎的な1つであり、他の9個は異なるプロトコルパッケージに対する拡張と適合であり、nettyがよく使われるプロトコルフォーマットと流行しているプロトコルフォーマットをサポートしていることがわかり、非常に強力である.codecの内容が非常に多いため、説明するのも容易ではありません.本稿ではnetty-codecを例に、その中で最も基本的で最も一般的な符号化デコーダを説明します.

codecの使用に注意すべき問題


nettyは便利なcodec符号化デコーダを提供していますが、前の記事で述べたように、Frame detectionと一緒に使用する必要があるcodecもあります.まずFrame detectionを使用してByteBufを実際のデータを表すByteBufに分割し、nettyに内蔵されたcodecまたはカスタムcodecに渡して処理すると、効果的です.

Netty内蔵の基本codec


Nettyの基本的なcodecにはbase 64、bytes、compression、json、marshalling、protobuf、serialization、string、xmlのいくつかがあります.
以下、一つ一つ説明します.

base64


このcodecは、ByteBufとbase 64以降のByteBufとの間の変換を担当する.いずれもByteBufからByteBufまでですが、その内容が変わりました.
Base 64 EncoderとBase 64 Decoderの2つの重要なクラスがあります.Base 64 Decoderは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はbytes配列とByteBufの間を変換し、同様にdecodeの前に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


compressionというパッケージの内容は比較的豊富で、主にデータの圧縮と解凍サービスです.サポートされるアルゴリズムは次のとおりです.
brotli
Bzip2
FastLZ
JdkZlib
Lz4
Lzf
Snappy
Zlib
Zstandard

compressionは、大きなデータ量の伝送に特に役立ち、圧縮により伝送されるデータ量を節約し、伝送速度を向上させることができる.
しかし、圧縮は特定のアルゴリズムを用いて計算されるので、高いCPUの操作であり、ネットワーク速度とCPU性能を両立させ、バランスをとる必要があります.

json


jsonこのパッケージにはJsonObjectDecoderクラスが1つしかありません.主にByteストリームのJSONオブジェクトまたは配列をJSONオブジェクトと配列に変換します.
JsonObjectDecoderは直接ByteToMesageDecoderのサブクラスであるため、FrameDecoderは不要であり、カッコの一致に基づいてByte配列の開始位置を判断し、どのByteデータが同じJsonオブジェクトまたは配列に属しているかを区別する.
JSONを使ってデータを転送したいなら、このクラスはとても役に立ちます.

marshalling


MarshallingのフルネームはJBoss Marshallingと呼ばれ、JBoss出品のオブジェクトをシーケンス化する方法ですが、JBoss Marshallingの最新APIは2011-04-27で、すでに10年も更新されていませんが、廃棄されているのではないでしょうか.
だからここではこのシーケンス化の内容を詳しく紹介しないで、興味のある仲間は自分で探求することができます.

protobuf


protobufはよく知られているはずですが、google出品の情報交換フォーマットであり、シーケンス化された方法と見なすことができます.これは言語中立、プラットフォーム中立、拡張性のある構造化データシーケンス化メカニズムであり、XMLと似ていますが、XMLよりも小さく、より速く、より簡単です.
Nettyのprotobufのサポートは、protobufのmessageおよびMessageLiteオブジェクトをByteBufに変換できることです.
protobufの2つのエンコーダもmessageからmessageへの直接的な変換なのでframe detectionも使用する必要があります.もちろん、LengthFieldPrependerやLengthFieldBasedFrameDecoderのような他のframe detectionも使用できます.
   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のために2つの専門的なframe detectionを用意しています.彼らはProtobufVarint 32 FrameDecoderとProtobufVarint 32 LengthFieldPrependerです.この2つのクラスを説明する前に、protobufのBase 128 Varintsについて理解する必要があります.
ヴァリエンスって何?つまり、整数をシーケンス化する場合、占有する空間の大きさは異なり、小さい整数が占有する空間は小さく、大きい整数が占有する空間は大きく、このように具体的な長さを固定する必要がなく、データの長さを減らすことができるが、解析の複雑さをもたらす.
では、このデータにはいったい何byteが必要なのか、どうやって知るのでしょうか.protobufでは、各byteの最上位は1つの判定ビットであり、このビットが1に置かれている場合は、後のbyteとそのbyteが一緒であることを示し、同じ数を示し、このビットが0に置かれている場合は、後のbyteとそのbyteが関係していないことを示し、このbyteにデータが終了する.
例えば、1つのbyteは8ビットであり、整数1を表す場合、以下のbyteで表すことができる.
0000 0001

1つのbyteに整数が入れられない場合は、次のデータが300を表すように、複数のbyteを使用して接続操作を行う必要があります.
1010 1100 0000 0010

どうして300ですか.まず最初のbyteを見て、その首位は1で、後ろにもう一つのbyteがあることを示します.2番目のbyteを見ると、トップは0で、これで終わりです.私たちは判断を外して、次の数字になります.
010 1100 000 0010

この場合、データの値を計算することはできません.protobufではbyteの桁数が逆なので、上の2つのbyteを位置を交換する必要があります.
000 0010 010 1100 

つまり、
10 010 1100 

=256 + 32 + 8 + 4 = 300
protobufでは一般にVarintがフィールドの長さビットとして使用されるため、nettyはProtobufVarint 32 LengthFieldPrependerとProtobufVarint 32 FrameDecoderがByteBufを変換することを提供する.
たとえば、ByteBufにvarintのlengthを追加します.
   BEFORE ENCODE (300 bytes)       AFTER ENCODE (302 bytes)
   +---------------+               +--------+---------------+
   | Protobuf Data |-------------->| Length | Protobuf Data |
   |  (300 bytes)  |               | 0xAC02 |  (300 bytes)  |
   +---------------+               +--------+---------------+

復号時にvarintのlengthフィールドを削除します.
   BEFORE DECODE (302 bytes)       AFTER DECODE (300 bytes)
   +--------+---------------+      +---------------+
   | Length | Protobuf Data |----->| Protobuf Data |
   | 0xAC02 |  (300 bytes)  |      |  (300 bytes)  |
   +--------+---------------+      +---------------+

serialization


シーケンス化とは,オブジェクトをバイナリデータに変換することであり,実際にはすべてのcodecがシーケンス化できる.オブジェクトとbyte間の変換方法を提供します.
Nettyは、ObjectDecoderとObjectEncoderの2つのオブジェクトの変換方法も提供します.
なお、この2つのオブジェクトとJDKが持つObjectInputStreamとObjectOutputStreamは互換性がなく、互換性がある場合はCompactObjectInputStream、CompactObjectOutputStream、CompatibleObjectEncoderを使用できます.

string


Stringは私たちが最もよく使うオブジェクトで、nettyはstringにStringDecoderとStringEncoderを提供しています.
同様に、この2つのクラスを使用する前に、メッセージを変換する必要があります.通常は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には独自の開始記号と終了記号があるので、frame detectionをする必要はありません.
   +-----+-----+-----------+
   |  |
   +-----+-----+-----------+
 :
   +-----------------+
   |  |
   +-----------------+
   +-----+-----+-----------+-----+----------------------------------+
   |  | content |
   +-----+-----+-----------+-----+----------------------------------+
    :
   +-----------------+-------------------------------------+
   |  | content |
   +-----------------+-------------------------------------+

すべて可能です.

まとめ


Nettyは多くの優秀なcodecを提供して各種の応用プロトコルに適して、みんなは多く使って、異なるプロトコルの違いを探すことができます.
この文書はhttp://www.flydean.com/16-netty-buildin-codec-common/に収録されています.
最も通俗的な解読、最も深い乾物、最も簡潔なチュートリアル、多くのあなたが知らない小さなテクニックなどを発見します!
私の公衆番号に注目することを歓迎します:“プログラムのあれらの事”、技術を理解して、更にあなたを理解します!