Google的Protobuf在业界非常流行,很多商业项目选择Protobuf作为编解码框架,其优点如下。
- 在谷歌内部长期使用,产品成熟度高:
- 跨语言,支持多种语言,包括C十十、java和Python.
- 编码后的消息更小,更加有利于存储和传输:
- 编解码的性能非常高:
- 支持不同协议版本的前向兼容:
- 支辫定义可选和必选字段。
Protobuf的入门
Protobuf是一个灵活、高效、结构化的数据序列化框架,相比于XML等传统的序列化工具,它更小,更快,更简单。Protobuf支持数据结构化一次可以到处使用,甚至跨语言使用,通过代码生成工具可以自动生成不同语言版本的源代码,甚至可以在使用不同版本的数据结构j进程间进行数据传递,实现数据结构的前向兼容。
下面我们通过一个简单的例程来学习如何使用Protobuf对POJO对象进行编解码,然后,我们以这个例程为基础,学习如何在Netty中对POJO对象迸行Protobuf编解码,并在两个进程之间进行通信和数据交换。
Protobuf开发环境搭建
首先下载Protobuf的Windows版本,得到protoc.exe.
下面我们以商品订购例程为例,定义SubscribeReq.proto和SubscribeResp.proto与protoc.exe放在同目录下(方便下面操作).
代码清单1 SubscribeReq.proto
代码清单2 SubscribeReq.proto
通过protoc.exe命令protoc --java_out=SubscribeReq.proto
和protoc --java_out=SubscribeResp.proto
行生成Java代码。如果出现Missing input file
则改用protoc ./SubscribeReq.proto --java_out=./
和protoc ./SubscribeResp.proto --java_out=./
如图1所示,再把生成的SubscribeReqProto.java和SubscribeRespProto.java拷贝到项目中。
图1 通过protoc.exe工具生成源代码
生成的源代码编译出错,是由于缺少protobuf-java的jar包,其maven的依赖如下,将jar包引入到类库中就能正常使用,Protobuf开发环境也已经构建完成。
代码清单3 protobuf-java的maven的依赖
Protobuf编解码开发
Protobuf的类库使用比较简单,下面我们就通过对SubscribeReqProto进行编解码来介绍Protobuf的使用。
代码清单4 Protobuf入门 TestSubscribeReqProto
运行Protobuf例程
运行TestSubscribeReqProto,执行结果如图2所示。
图2 运行TestSubscribeReqProto执行结果
Netty的Protobuf服务端开发
下面为一个Protobuf版本的图书订购程序。
Protobuf服务端开发
代码清单5 Protobuf版本图书订购代码SubReqServer
代码清单6 Protobuf版本图书订购代码SubReqServerHandler
由于protobufDecoder已经对消息进行了自动解码,因此接收到的订购请求消息可以直接使用。对用户名进行校验,校验通过后构造应答消息返回给客户端,由于使用了ProtobufEncoder,所以不需要对SubscribeRespProto.SubscribeResp进行手工编码。
Protobuf客户端开发
代码清单7 Protobuf版本图书订购代码SubReqClient
代码清单8 Protobuf版本图书订购代码SubReqHandler
测试Protobuf版本的图书订购程序功能
服务端运行结果如图3所示.
图3 服务端运行结果
服务端运行结果如图4所示.
图4 服务端运行结果
Protobuf的使用注意事项
ProtoBufDecoder仅仅负责解码,它不支持读半包。因此,在ProtobufDecoder前面,一定要有能够处理读半包的解码器,有以下三种方式可以选择。
- 使用Netty提供的ProtobufVarint32FrameDecoder,可以处理半包消息;
- 继承Netty的通用半包解码器LengthFieldBasedFrameDecoder;
- 继承ByteToMessageDecoder类,自己处理半包消息。
如果使用ProtobufDecoder解码器而忽略对半包消息的处理,程序是不能正常工作的。以前面的图书订购为例服务端代码进行修改,注释掉ProtobufVarint32FrameDecoder,代码修改如图5所示。
图5 注释掉ProtobufVarint32FrameDecoder
程序运行,结果如图6所示,运行出错。
图6 注释掉ProtobufVarint32FrameDecoder运行出错