ProtoBuf

编码和解码


  1. 数据在网络中的传输都是以二进制字节码数据,在发送时需要编码,接收时需要解码。
  2. codec由两部分组成,decoder(解码器)和 encoder(编码器)

Netty的编码和解码


Netty提供的编码器:

  • StringEncoder
  • ObjectEncoder

Netty提供的解码器:

  • StringDecoder
  • ObjectDecoder

Netty自带的编码解码器,底层使用的时Java的序列化技术,Java的序列化技术效率不高,而且存在以下问题;

  • 不能跨语言,Server和Client都必须是Java
  • 序列化后体积太大,是二进制编码的5倍多
  • 性能太低

为解决这些问题,Google提供了ProtoBuf

ProtoBuf


Google发布的开源项目,全程Goole Protocol Buffers。
是一种高效的结构化数据存储方式,可以用来序列化。很适合做数据存储和RPC的数据交换格式。

使用protoBuf的实例:

  1. 下载ProtoBuf
  2. 项目导入protoBuf
		<dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.6.1</version>
        </dependency>
  1. 编写proto文件
    Student.proto
syntax="proto3"; // 声明版本
option java_outer_classname="StudentPOJO"; //指定外部类
message Student{
    int32 id=1;
    string name=2;
}
  1. 使用protoc.exe生成Java文件
protoc.exe --java_out=. Student.proto
  1. 编写客户端处理器和服务端处理器
    ClientHandler
	// 在管道激活时发送一个Student对象
	@Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 发送一个student对象到服务器
        // Student时StudentPOJO的内部类
        StudentPOJO.Student student = StudentPOJO.Student.newBuilder().setId(10).setName("张三").build();
        ctx.writeAndFlush(student);
    }

ServerHandler

	@Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    	// 强转即可使用
        StudentPOJO.Student student = (StudentPOJO.Student) msg;
        System.out.println(student.getId() + student.getName());
    }

服务端和客户端分别添加解码器和编码器:

Server:

// 指定解码器,并指定对哪种对象解码
pipeline.addLast(new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance()));
//添加自定义Handler
pipeline.addLast(new ServerHandler());

Client:

// 添加编码器
pipeline.addLast(new ProtobufEncoder());
//添加自定义的Handler
pipeline.addLast(new ClientHandler());
  1. 先后启动Server、Client

服务器控制台打印:

10张三

成功接收到客户端发送的对象。


虽然成功接收到Student对象,但如果想要发送其他对象则又需要编写proto文件,着实麻烦。

解决办法
编写proto文件,使用一个message来管理其他的message。在管理的message中,添加一个标识,用于标识发送过来的是哪一个的类的对象。

实例如下:

syntax = "proto3";  // 指定版本
option optimize_for = SPEED; // 加快解析
option java_package = "com.xing.netty.codec2"; //指定包位置
option java_outer_classname = "MyDataInfo"; //外部类名
// protoBuf可以使用message管理其他的message
message MyMessage{

    // MyMessage的第一个属性,用data_type来标传的是哪一个枚举类型
    DataType data_type = 1;

    // 每次只能有一个枚举类型,节省空间
    oneof dataBody{
        Student student = 2;
        Worker worker = 3;
    }

}

// 枚举类型
enum DataType{
    // enum中编号从0开始
    StudentType = 0;
    WorkType = 1;
}

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

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

生成MyDataInfo.java文件。

Server添加MyDataInfo的解码器:

// 指定解码器,并指定对哪种对象解码
pipeline.addLast(new ProtobufDecoder(MyDataInfo.MyMessage.getDefaultInstance()));
pipeline.addLast(new ServerHandler());

经过测试可以发送Student和Worker对象。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值