Nettyシリアル化(1)-ProtoBuf

Javaシリアライゼーションには、主に2つの目的があります。1。ネットワーク送信、2。オブジェクトの永続性

リモートサービスが呼び出されるとき、転送されたJavaオブジェクトをバイト配列またはByteBufferオブジェクトとしてエンコードする必要があります。リモートサービスがByteBufferオブジェクトまたはバイト配列を読み取る場合、送信時にJavaオブジェクトにデコードする必要があります。これは、Javaオブジェクトコーデックテクノロジと呼ばれます。

Javaシリアル化はJDK 1.1バージョンから提供されており、追加のクラスライブラリを追加する必要はありません。java.io.Serializableを実装してシリアルIDを生成するだけでよいため、誕生以来広く使用されています。しかし、リモートサービス呼び出し(RPC)では、Javaシリアル化がメッセージのエンコード、デコード、および送信に直接使用されることはほとんどありません。

  1. 言語をまたぐことはできません
  2. シリアル化されたコードストリームが大きすぎます
  3. シリアル化のパフォーマンスが低すぎる

クロスプロセスサービス呼び出しの場合、サービスプロバイダーはC ++または他の言語を使用して開発を行うことがありますが、異種言語プロセスとやり取りする必要がある場合、Javaシリアル化は適切ではありません。JavaシリアライゼーションテクノロジーはJava言語内のプライベートプロトコルであるため、他の言語ではサポートされておらず、ユーザーにとって完全にブラックボックスです。Javaによってシリアル化されたバイト配列の場合、他の言語を逆シリアル化することはできません。これは、そのアプリケーションを著しく妨害します。そして、Javaシリアライゼーションは、それがシリアライズされたコードストリームのサイズであろうと、シリアライゼーションのパフォーマンスであろうと、JDKのデフォルトのシリアライゼーションメカニズムは非常にうまく機能しません。したがって、リモートクロスノードコールのコーデックフレームワークとしてJavaシリアル化を選択しないことがよくあります。




ネッティーは、私たちが最初にいるProtobufの使用を導入する必要があるプロトコルバッファとJBossマーシャリング、ためのサポートを内蔵し、最初にすべての私たちができるhttps://github.com/protocolbuffers/protobuf/releasesバージョンを選択しprotoc-xxx-win32.zip、ダウンロードにして、解凍し、圧縮されていないprotoc.exeを完全な英語パスに入れ、そのパス名をWindows環境変数の下のパスの下に置きます(C:\ Windows \ System32の下に直接置くこともできます) 。


次に、User.protoファイルを準備します。内容は次のとおりです。Userクラスを定義します。名前、年齢、性別の3つのプロパティがあります。java_packageの値はプロジェクトと一致している必要があります

syntax = "proto2";
option java_package="com.protobuf.serlizable";
option java_outer_classname="UserProtoBuf";

message User{
        required string name = 1;
        optional int32 age = 2;
        optional string sex = 3;
}

次に、コマンドラインで次のコマンドを使用してJavaクラスを生成できます。

protoc -I =ソースアドレス--java_out =ターゲットアドレスソースアドレス/ xxx.proto

ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入


次に、上記で生成されたUserProtoBufクラスをプロジェクトにコピーできます。ここで、パッケージ名は生成時に一貫している必要があります。そうでない場合、プロジェクトでエラーが報告され、関連する依存関係を追加することを忘れないでください

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.11.1</version>
</dependency>

もちろん、プロジェクトには次のような関連JavaBeansがあります。

public class User{
    private String name;
    private int age;
    private String sex;
}

ネッティーはその後、前にほとんどここのサービスの私達の標準、クライアント、であり、我々はネッティーは、サーバとクライアントがHTTPを実現使う、合意繰り返すことはしません、次のように、クライアントコードは次のとおりです。

public class NettyClient {

    public static void main(String[] args) throws Exception {
        NettyClient client = new NettyClient();
        client.connect("127.0.0.1", 8888);
    }

    private void connect(String host, int port) throws Exception{
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
                            ch.pipeline().addLast(new ProtobufEncoder());
                            ch.pipeline().addLast(new ProtobufClientHandler());
                        }
                    });

            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}
public class ProtobufClientHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        UserProtoBuf.User.Builder builder = UserProtoBuf.User.newBuilder();
        builder.setName("Kimi").setAge(18).setSex("男");
        ctx.writeAndFlush(builder.build());
    }
}

クライアントコードでは、下の図に示すように、最初のコードは主にスティッキーハーフパケットの問題を解決するために使用され、メッセージの長さフィールドを追加するために使用されます。メッセージは、メッセージヘッダーとメッセージ本文に分かれています。2つ目は主にシリアル化に使用され、エンティティクラスをバイトに変換して送信します。
ここに画像の説明を挿入



次に、サーバー側の関連コードを次のように見てみましょう。

public class NettyServer {

    public static void main(String[] args) throws Exception {
        NettyServer server = new NettyServer();
        server.bind(8888);
    }

    private void bind(int port) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        try {
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 512)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
                            ch.pipeline().addLast(new ProtobufDecoder(UserProtoBuf.User.getDefaultInstance()));
                            ch.pipeline().addLast(new ProtobufServerHandler());
                        }
                    });

            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
public class ProtobufServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        UserProtoBuf.User user = (UserProtoBuf.User) msg;
        System.out.println("姓名:" + user.getName() + ",年龄:" + user.getAge() + ",性别:" + user.getSex());
    }
}

クライアントには、サーバーに関連するコーデックもあります。最初のコーデックは、データパケットの長さフィールドを分離して実際のデータを取得するために使用されます。2つ目は、バイトをエンティティークラスにデコードする逆シリアル化に使用されます。
ここに画像の説明を挿入


次に、関連するテストを次のように実行します。
ここに画像の説明を挿入

結果は成功しました。プログラムの開始後、クライアントはエンティティクラスをサーバーに送信しました。シリアル化および逆シリアル化を通じて、サーバーはデータを正常に取得しました。サーバーがエンティティクラスをクライアントに送信した場合、 、それは問題です。サーバーとクライアントに追加されたコーデックを逆にして、関連するコーデックを再度追加するだけで済みます。

286の元の記事が公開されました Liked12 訪問者10,000以上

おすすめ

転載: blog.csdn.net/newbie0107/article/details/104441475