0
点赞
收藏
分享

微信扫一扫

netty之Protobuf序列化协议

IT影子 2022-04-14 阅读 41
后端

前言

一般我们在开始使用netty的时候,都习惯性的会用json/fastjson等来进行序列化,这个并没有什么问题,但是如果对性能有非常高的要求,那就需要用到其他的序列化协议了,目前用的比较广泛和性能比较高的就是Protobuf。

下载安装

官方下载链接
下载编译器:protoc-3.20.0-win64.zip,配置编译器到环境变量
官方文档地址

数据类型对比
在这里插入图片描述

  • repeated:指定字段为集合,对应到java文件里,生成的是List。
  • optional:指定字段为可选字段,可以为空,对于optional字段还可以使用 [default] 指定默认值,如果没有指定,则会使用字段类型的默认值。

编辑proto文件
基本使用

syntax="proto3";
option optimize_for=SPEED;//加快解析
//定义protobuf的包名称空间
option java_package = "com.hwdz.compute.entity";
// 消息体名称
option java_outer_classname = "ProtoMsg";
//.....

/*聊天消息*/
message MessageRequest{
    uint64 msg_id = 1;       
    string from = 2;     
    string to = 3;          
    uint64 time = 4;     
    uint32 msg_type = 5; 
    string content = 6; 
    string url = 7;     
    string property = 8; 
    string from_nick = 9; 
    optional string json = 10; 
}

进阶版-如果根据传递过来数据进行对应的解析,可以这样做

syntax="proto3";
option optimize_for=SPEED;//加快解析
option java_package="com.hwdz.compute.entity"; //指定生成到那个包下
option java_outer_classname="MyDataInfo"; //指定外部类名称
//protobuf 可以使用message 管理其他message
message MyMessage{
  //定义一个枚举
  enum DataType{
    StudentType=0; //在proto3 要求enum编号从0开始
    WorkerType=1;
  }
  DataType data_type=1;  //用data_type标识传的是哪一个枚举类型
  //oneof表示每次枚举类型最多只能出现定义的message(Student、Worker)的其中一个
  oneof dataBody{
    Student student =2;
    Worker worker =3;
  }

}
message Student{
  int32 id=1; //Student类的属性
  string name =2;
}
message Worker{
  string name=1; //Student类的属性
  int32 age =2;
}

maven依赖

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

编写服务端代码:
这里只展示核心代码,其他的可以参考专栏下netty搭建代码

首先是针对数据的编解码器和防止拆包粘包的编解码器,protobuf在高并发下是存在粘包拆包的现象

 	  //防止粘包拆包
	  pipeline.addLast(new ProtobufVarint32FrameDecoder());
	  pipeline.addLast("decoder", new ProtobufDecoder(MyDataInfo.MyMessage.getDefaultInstance()));
	  //防止粘包拆包
	  pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
	  pipeline.addLast("encoder", new ProtobufEncoder());

handler处理器

	@Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        //根据dataType显示不同信息
        MyDataInfo.MyMessage myMessage = (MyDataInfo.MyMessage) msg;
        MyDataInfo.MyMessage.DataType dataType = myMessage.getDataType();
        if (dataType == MyDataInfo.MyMessage.DataType.StudentType) {
            MyDataInfo.Student student = myMessage.getStudent();
            System.out.println("学生id="+student.getId()+"学生姓名="+student.getName());
        } else if (dataType == MyDataInfo.MyMessage.DataType.WorkerType) {
            MyDataInfo.Worker worker = myMessage.getWorker();
            System.out.println("工人年龄="+worker.getAge()+"工人姓名="+worker.getName());
        } else {
            System.out.println("传输的类型不正确");
        }
    }

编写客户端代码:

MyDataInfo.MyMessage myMessage = MyDataInfo.MyMessage.newBuilder().setDataType(MyDataInfo.MyMessage.DataType.StudentType)
                    .setStudent(MyDataInfo.Student.newBuilder().setId(5).setName("玉麒麟").build()).build();
tx.writeAndFlush(myMessage);

注意一点:记得改泛型,如果你用的是SimpleChannelInboundHandler

public class NettyClientHandler extends SimpleChannelInboundHandler<MyDataInfo.MyMessage> {

当然还有心跳消息,之前用的是字符串ping,现在换编解码器了之后会报错,可以改一下这个实体类,加一个心跳的消息类型。

举报

相关推荐

Protobuf数据序列化

0 条评论