Netty-Protobuf编解码

127 阅读1分钟

Java的序列化和反序列化性能是很低的,序列化后的字节流大,无法跨语言。一些主流的编解码器性能可观,得到了广泛的认可,如 Marshaling、Protobuf、MessagePack等,Netty对主流的编解码器都有实现,我们看下其中的一个Protobuf是怎么使用的。

生成java文件

下载文件

github.com/protocolbuf…

image.png

定义.proto文件

protobuf.dev/programming…

image.png

我们这里定义两个文件

syntax = "proto3";

message SearchReq {
  string name = 1;
  int32 age = 2;
}
syntax = "proto3";

message SearchResp {
  string name = 1;
  int32 age = 2;
}

执行命令生成文件

image.png

image.png

image.png

Netty 使用Protobuf

将生成的类拷贝到项目中

image.png

image.png

添加protobuf依赖

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

NettyServer

public class NettyServer {

    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new ProtobufVarint32FrameDecoder());
                            socketChannel.pipeline().addLast(new ProtobufDecoder(SearchReqOuterClass.SearchReq.getDefaultInstance()));
                            socketChannel.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
                            socketChannel.pipeline().addLast(new ProtobufEncoder());
                            socketChannel.pipeline().addLast(new NIOServerHandler());
                        }
                    });
            ChannelFuture sync = bootstrap.bind(new InetSocketAddress(8080)).sync();
            sync.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }


    }

}

NIOServerHandler

public class NIOServerHandler extends SimpleChannelInboundHandler {


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        //接收客户端的数据
        SearchReqOuterClass.SearchReq message = (SearchReqOuterClass.SearchReq) msg;
        System.out.println("服务端接收到客户端的消息:" + message.toString());

        //响应给客户端
        SearchRespOuterClass.SearchResp.Builder builder = SearchRespOuterClass.SearchResp.newBuilder();

        builder.setAge(100);
        builder.setName("响应给客户端的数据");
        SearchRespOuterClass.SearchResp build = builder.build();
        ctx.writeAndFlush(build);

    }
}

NettyClient

public class NettyClient {

    public static void main(String[] args) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        try {

            Bootstrap handler = bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
                            ch.pipeline().addLast(new ProtobufDecoder(SearchRespOuterClass.SearchResp.getDefaultInstance()));
                            ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
                            ch.pipeline().addLast(new ProtobufEncoder());
                            ch.pipeline().addLast(new NioClientHandler());
                        }
                    });

            ChannelFuture sync = handler.connect(new InetSocketAddress("127.0.0.1", 8080)).sync();
            sync.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            group.shutdownGracefully();
        }

    }
}

NioClientHandler

public class NioClientHandler extends ChannelInboundHandlerAdapter {


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //发送数据给服务器
        SearchReqOuterClass.SearchReq.Builder builder = SearchReqOuterClass.SearchReq.newBuilder();
        builder.setName("给服务器的数据");
        builder.setAge(100);
        SearchReqOuterClass.SearchReq searchReq = builder.build();
        ctx.writeAndFlush(searchReq);


    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        SearchRespOuterClass.SearchResp searchResp = (SearchRespOuterClass.SearchResp) msg;
        System.out.println("接收来自服务器数据:" + searchResp.toString());


    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

测试程序

image.png

image.png