• Netty-编码和解码


    编码和解码的基本介绍

    1. 编写网络应用程序时,因为数据在网络中传输的都是二进制字节码数据,在发送数据时就需要编码,接收数据时就需要解码
    2. codec(编解码器) 的组成部分有两个:decoder(解码器)和 encoder(编码器)。encoder 负责把业务数据转换成字节码数据,decoder 负责把字节码数据转换成业务数据

    在这里插入图片描述

    Netty 本身的编码解码的机制和问题分析

    1. Netty 自身提供了一些 codec(编解码器)
    2. Netty 提供的编码器
      • StringEncoder,对字符串数据进行编码
      • ObjectEncoder,对 Java 对象进行编码
      • …
    3. Netty 提供的解码器
      • StringDecoder, 对字符串数据进行解码
      • ObjectDecoder,对 Java 对象进行解码
      • … 4) Netty 本身自带的 ObjectDecoder 和 ObjectEncoder 可以用来实现 POJO 对象或各种业务对象的编码和解码,底层使用的仍是 Java 序列化技术 , 而Java 序列化技术本身效率就不高,存在如下问题
      • 无法跨语言
      • 序列化后的体积太大,是二进制编码的 5 倍多。
      • 序列化性能太

    Protobuf基本介绍和使用示意图

    1. Protobuf 是 Google 发布的开源项目,全称 Google Protocol Buffers,是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC[远程过程调用 remote procedure call ] 数据交换格式 。目前很多公司 http+json  tcp+protobuf
    2. 参考文档 : https://developers.google.com/protocol-buffers/docs/proto 语言指南
    3. Protobuf 是以 message 的方式来管理数据的.
    4. 支持跨平台、跨语言,即[客户端和服务器端可以是同的语言编写的] (支持目前绝大多数语言,例如 C++、C#、Java、python 等)
    5. 高性能,高可靠性
    6. 使用 protobuf 编译器能自动生成代码,Protobuf 是将类的定义使用.proto 文件进行描述。说明,在idea 中编写 .proto 文件时,会自动提示是否下载 .ptotot 编写插件. 可以让语法高亮。
    7. 然后通过 protoc.exe 编译器根据.proto 自动生成.java 文件
    8. protobuf 使用示意图
      在这里插入图片描述

    使用

    pom.xml

     <properties>
         <maven.compiler.source>8maven.compiler.source>
         <maven.compiler.target>8maven.compiler.target>
         
         <protobuf.version>3.6.1protobuf.version>
         
     properties>
    
    
     <dependencies>
         <dependency>
             <groupId>com.google.protobufgroupId>
             <artifactId>protobuf-java-utilartifactId>
             <version>${protobuf.version}version>
         dependency>
     dependencies>
    
     <build>
         <defaultGoal>packagedefaultGoal>
         <extensions>
             <extension>
                 <groupId>kr.motd.mavengroupId>
                 <artifactId>os-maven-pluginartifactId>
                 <version>1.5.0.Finalversion>
             extension>
         extensions>
    
         <plugins>
             
             <plugin>
                 <groupId>org.xolstice.maven.pluginsgroupId>
                 <artifactId>protobuf-maven-pluginartifactId>
                 <version>0.5.1version>
                 <extensions>trueextensions>
                 <configuration>
                     <protoSourceRoot>${project.basedir}/src/main/java/com/jhj/netty/protoprotoSourceRoot>
                     <protocArtifact>com.google.protobuf:protoc:3.2.0:exe:${os.detected.classifier}protocArtifact>
                 configuration>
                 <executions>
                     <execution>
                         <goals>
                             <goal>compilegoal>
                         goals>
                     execution>
                 executions>
             plugin>
    
             
             <plugin>
                 <groupId>org.apache.maven.pluginsgroupId>
                 <artifactId>maven-compiler-pluginartifactId>
                 <version>3.1version>
                 <configuration>
                     <source>${java.version}source>
                     <target>${java.version}target>
                 configuration>
             plugin>
         plugins>
     build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    安装插件

    Protobuf

    发送单一对象

    Student.proto文件
    syntax = "proto3";
    option java_outer_classname = "StudentPOJO"; //生成的外部类名,同时也是文件名
    message Student{
        int32 id=1; //Student 类中有 一个属性 名字为id 类型为 int32(proto 类型) 1表示属性序号,不是值
        string name=2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    利用插件转换

    在这里插入图片描述

    将target中编译后的class文件拿过来
    客户端加入到pipeline
    ch.pipeline().addLast("encoder",new ProtobufEncoder());//在pieline中加入ProtoBufEncoder
    
    • 1
    客户端发送一个对象
    //发送一个student 对象
    StudentPOJO.Student jhj =StudentPOJO.Student.newBuilder().setId(101).setName("jhj").build();
    
    ctx.writeAndFlush(jhj);
    
    • 1
    • 2
    • 3
    • 4
    服务端加入到piepline
    ch.pipeline().addLast("decoder",new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance()));//加入ProtoBufDecoder
    
    
    • 1
    • 2
    服务端监听
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    
        //读取从客户端发送的StudentPojo.student
        StudentPOJO.Student student = (StudentPOJO.Student) msg;
    
        System.out.println("客户端发送消息是:" + student.getId()+student.getName());
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    发送两个对象

    protobuf文件
    syntax = "proto3";
    option optimize_for = SPEED; //加快解析
    option java_package = "com.jhj.netty.protobuf2"; //指定生成到哪个包下
    option java_outer_classname = "MyDataInfo"; //生成的外部类名,同时也是文件名
    
    //protobuf 可以使用message 管理其他的message
    
    message MyMessage{
        //定义一个枚举类型
        enum DataType{
            StudentType=0;//在prop3 要求enum的编号从0开始
            WorkerType=1;
        }
    
        //用data_type 来标识传的是哪一个枚举类型
        DataType data_type = 1;
    
        //标识每次枚举类型最多只能出现其中的一个,节省空间
        oneof dataBody{
            Student student = 2;
            Worker worker = 3;
        }
    }
    
    message Student{
        int32 id=1; //Student 类中有 一个属性 名字为id 类型为 int32(proto 类型) 1表示属性序号,不是值
        string name=2;
    }
    
    message Worker{
        string name=1;
        int32 age=2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    将target中编译后的class文件拿过来
    客户端加入到pipeline
    ch.pipeline().addLast("encoder",new ProtobufEncoder());//在pieline中加入ProtoBufEncoder
    
    • 1
    客户端发送一个对象
     @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
    
         //随机发送Student 或者 Worker对象
         int random = new Random().nextInt(3);
         MyDataInfo.MyMessage myMessage=null;
         if (0==random){
             myMessage=MyDataInfo.MyMessage.newBuilder().setDataType(MyDataInfo.MyMessage.DataType.StudentType).setStudent(MyDataInfo.Student.newBuilder().setId(5).setName("jhj student").build()).build();
         }else{
             myMessage=MyDataInfo.MyMessage.newBuilder().setDataType(MyDataInfo.MyMessage.DataType.WorkerType).setWorker(MyDataInfo.Worker.newBuilder().setAge(5).setName("jhj").build()).build();
         }
         ctx.writeAndFlush(myMessage);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    服务端加入到piepline
    ch.pipeline().addLast("decoder",new ProtobufDecoder(MyDataInfo.MyMessage.getDefaultInstance()));//加入ProtoBufDecoder
    
    
    • 1
    • 2
    服务端监听
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    
         //读取从客户端发送的StudentPojo.student
         MyDataInfo.MyMessage myMessage = (MyDataInfo.MyMessage) msg;
         MyDataInfo.MyMessage.DataType dataType = myMessage.getDataType();
         if (dataType== MyDataInfo.MyMessage.DataType.StudentType){
             System.out.println("客户端发送消息是:" + myMessage.getStudent().getId()+myMessage.getStudent().getName());
    
         }else if (dataType== MyDataInfo.MyMessage.DataType.WorkerType) {
             System.out.println("客户端发送消息是:" + myMessage.getWorker().getAge()+myMessage.getWorker().getName());
         }else {
             System.out.println("参数不对");
         }
    
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    作者声明

    如有问题,欢迎指正!
    
    • 1
  • 相关阅读:
    尾矿库监测 GNSS北斗高精度定位终端机应用
    springboot集成swagger3.0
    Unity之使用贝塞尔曲线制作图片轮播
    使用腾讯云发送短信 ---- 手把手教你搞定所有步骤
    从产品销量考虑渠道布局——洗衣机行业数据分析
    (黑马出品_02)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
    C++复习数据类型总结
    路科验证-实验一详细步骤
    CIFAR-10 数据集简介
    华为昇腾云平台适配Baichuan2大模型记录
  • 原文地址:https://blog.csdn.net/weixin_45247019/article/details/126785717