(十三)Netty编解码器GoogleProtobuf介绍

Netty本身提供了一些编解码器如StringDecoder StringEncoder OjectDecoder ObjectEncoder,可以序列化JAVA的POJO对象,底层使用的java的序列化技术,java序列化本身效率不高,体积大,所有由Google开源了一个新的解决方案Google Protocol Buffers。

Google Protocol Buffers 是一个轻量级高效的结构化数据存储格式,可以用于数据的序列化,非常适合用于在远程调用RPC中做数据存储和数据交换。跨平台,跨语言(客户端和服务器可以使用不同的语言进行通信),支持大多数主流语言。通过protobuf的编译器通过.proto文件自动生成java类。

语法参考官网

基本使用
  1. 创建一个proto文件 描述需要被序列化的类

    syntax = "proto3";
    
    
    // option配置java文件输出的class名 同时也是文件名
    option java_outer_classname="StudentPojo";
    option optimize_for=SPEED;//加快解析
    option java_package="com.ycorn.nettypractices.protobuf"; // 生成放在哪个包下
    
    // message 关键字用于管理一个结构化数据 类似 class
    // 在StudentPojo 类的里面生成pr一个Student的内部类 是真正发送的对象
    message Student{
        // 定义枚举 必须从0开始
        enum Gender {
            MALE = 0;
            FEMALE = 1;
        }
    
        int32 id = 1; // 有一个属性名为id 类型是32位int 1表示序列号不是值
        string name = 2;
        int32 age = 4;
        // 使用之前定义的枚举
        Gender gender=3;
    
    }
    
  2. 使用proto编译器将.proto文件编译成java文件

    protoc.exe xxx.proto --java_out=Dir
    
  3. 编写服务端和客户端java代码

    添加goole protobuf 相关依赖

         <dependency>
                <groupId>com.google.protobuf</groupId>
                <artifactId>protobuf-java</artifactId>
                <version>3.6.1</version>
            </dependency>
    
    public class ProtoBufServerDemo {
    
        public static void main(String[] args) {
            NioEventLoopGroup bossGroup = new NioEventLoopGroup();
            NioEventLoopGroup workerGroup = new NioEventLoopGroup();
    
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //解码器,通过Google Protocol Buffers序列化框架动态的切割接收到的ByteBuf
                            pipeline.addLast(new ProtobufVarint32FrameDecoder());
                            //服务器端接收的是客户端StudentPojo对象, 需要进行解码
                            pipeline.addLast(new ProtobufDecoder(StudentPojo.Student.getDefaultInstance()));
                            //Google Protocol Buffers编码器
                            pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
                            //Google Protocol Buffers编码器
                            pipeline.addLast(new ProtobufEncoder());
                            pipeline.addLast(new ProtoBufServerHandler());
                        }
                    });
    
            try {
                ChannelFuture future = serverBootstrap.bind(4444).sync();
                future.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    
    
    // 服务端处理器
    public class ProtoBufServerHandler extends SimpleChannelInboundHandler<StudentPojo.Student> {
    
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, StudentPojo.Student msg) throws Exception {
            System.out.println(String.format("收到客户端%s的信息: %s", ctx.channel().remoteAddress(), msg.toString()));
        }
    
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            StudentPojo.Student student = StudentPojo.Student.newBuilder().setId(1).setGender(StudentPojo.Student.Gender.MALE).setAge(30).build();
            ctx.channel().writeAndFlush(student);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }
    
    
    // 客户端
    public class ProtoBufClientDemo {
    
        public static void main(String[] args) {
            NioEventLoopGroup worker = new NioEventLoopGroup();
            Bootstrap bootstrap = new Bootstrap();
    
            bootstrap.group(worker)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //解码器,通过Google Protocol Buffers序列化框架动态的切割接收到的ByteBuf
                            pipeline.addLast(new ProtobufVarint32FrameDecoder());
                            //服务器端接收的是客户端StudentPojo对象, 需要进行解码
                            pipeline.addLast(new ProtobufDecoder(StudentPojo.Student.getDefaultInstance()));
                            //Google Protocol Buffers编码器
                            pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
                            //Google Protocol Buffers编码器
                            pipeline.addLast(new ProtobufEncoder());
                            // 自定义handler
                            pipeline.addLast(new ProtoBufClientHandler());
                        }
                    });
    
            try {
                ChannelFuture future = bootstrap.connect("localhost", 4444).sync();
                future.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                worker.shutdownGracefully();
            }
        }
    }
    
    
    // 客户端处理器
    public class ProtoBufClientHandler extends SimpleChannelInboundHandler<StudentPojo.Student> {
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            StudentPojo.Student stu = StudentPojo.Student.newBuilder().setAge(10).setId(1).setName("student from client").build();
            ctx.channel().writeAndFlush(stu);
        }
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, StudentPojo.Student msg) throws Exception {
            System.out.println("收到服务器的对象 " + msg);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }
    
  4. 核心总结

    几个核心的protobuf处理器

    1. ProtobufVarint32FrameDecoder: 这是针对protobuf协议的ProtobufVarint32LengthFieldPrepender()所加的长度属性的解码器 解决粘包拆包问题 可选
    2. ProtobufDecoder 解码器 必选
    3. ProtobufVarint32LengthFieldPrepender: 对protobuf协议的的消息头上加上一个长度为32的整形字段,用于标志这个消息的长度 解决粘包拆包问题 可选
    4. ProtobufEncoder: 编码器 必选
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值