官方文档:https://developers.google.cn/protocol-buffers/docs/overview
简介:
protocol buffers – a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more.
一种与语言无关,平台无关,可扩展的序列化结构化数据的方法,用于通信协议,数据存储等。
What are protocol buffers? 什么是protocol buffer?
Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. You can even update your data structure without breaking deployed programs that are compiled against the "old" format.
Protocol buffers 是一种灵活,高效,自动化的机制,用于序列化结构化数据 - 想想XML,但更小,更快,更简单。您可以定义数据的结构化结构,然后使用特殊生成的源代码轻松地将结构化数据写入和读取各种数据流,并使用各种语言。您甚至可以更新数据结构,而不会破坏根据“旧”格式编译的已部署程序。
How do they work? protobuf 是如何工作的?
上面的都是protocol buffer的官方资料,下面的...也是基于官方资料的。
基本约定:
1.我们使用的是protobuf 3.0版本协议,理由:简介,新一代,还有其他好处
2.对于3.0和2.0的区别大家可以在网上找资料查阅,这里不作介绍
3.阅读下面文字之前你最好先看下官网
protobuf数据类型转换
.proto Type | Notes | C++ Type | Java Type | Python Type[2] | Go Type | Ruby Type | C# Type | PHP Type | Dart Type |
---|---|---|---|---|---|---|---|---|---|
double | double | double | float | float64 | Float | double | float | double | |
float | float | float | float | float32 | Float | float | float | double | |
int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long[3] | int64 | Bignum | long | integer/string[5] | Int64 |
uint32 | Uses variable-length encoding. | uint32 | int[1] | int/long[3] | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
uint64 | Uses variable-length encoding. | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong | integer/string[5] | Int64 |
sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long[3] | int64 | Bignum | long | integer/string[5] | Int64 |
fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 228. | uint32 | int[1] | int/long[3] | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 256. | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong | integer/string[5] | Int64 |
sfixed32 | Always four bytes. | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sfixed64 | Always eight bytes. | int64 | long | int/long[3] | int64 | Bignum | long | integer/string[5] | Int64 |
bool | bool | boolean | bool | bool | TrueClass/FalseClass | bool | boolean | bool | |
string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode[4] | string | String (UTF-8) | string | string | String |
bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | String (ASCII-8BIT) | ByteString | string |
protobuf依赖maven包:
<dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.8.0</version> </dependency> |
一.创建proto协议文件
要想使用protobuf ,我们首先要按照protobuf的格式写一个.proto的消息协议文件
油耗上报协议文件brakingInfoReport.proto
//协议版本号
syntax = "proto3";
//引用外部proto协议文件
import "common.proto";
//协议所属包名
package coom.lyh.protobuf.demo.protos;
//对外输出 java包名
option java_package = "com.lyh.protobuf.demo.business";
//对外输出 java类名
option java_outer_classname = "BrakingInfoReportProto";
//定义上报消息实体
message BrakingInfoReport{
message BrakingInfo{
/**
* 事件产生的时间(单位毫秒)
*/
//private Long rts;
int64 rts = 1;
//private Float bol;
float bol = 2;
}
//消息类型 在common协议里面定义
JsonMessageType jsonMessageType = 1;
//对象类型 在common协议里面定义
ObjectMessageType objectMessageType = 2;
//mqtt协议版本号
string protocol = 3 ;
string sn = 4;
string carModelId = 5;
/**
* 消息传输时间(单位毫秒)
**/
int64 ts = 6;
/**
* 时间类型
**/
string et = 7;
/**
* 行程ID
*/
int32 tripId = 8;
//信息list
repeated BrakingInfo data = 9;
}
common.proto协议定义如下从协议文件中我们从注释中很容易理解这个消息中的各个量的意义,重点说下油耗消息协议文件引入了一个外部的common.proto协议文件
//proto 协议版本号
syntax = "proto3";
//输出java包名
option java_package = "com.lyh.protobuf.demo.business";
//输出java类名
option java_outer_classname = "Common";
//定义公共消息类型
enum JsonMessageType {
REPORT = 0;
REQUEST = 1;
RESPONSE = 2;
}
//定义公共消息传输对象类型
enum ObjectMessageType{
CONNECT_REQUEST= 0 ;
REPORT_BRAKING_INFO= 1 ;
}
二.编译proto协议到java文件common里面定义了我们的JsonMessageType 和ObjectMessageType 两个enum类型以供油耗协议使用,和java很类似,下面我们将这两个协议转成java对象
step 1:
下载官方的编译器,地址:https://github.com/protocolbuffers/protobuf/releases/tag/v3.8.0
选择适合自己OS的版本下载。
step 2:
2.1)将解压后的protoc.exe 添加到系统变量的path路径里面 我的电脑右键属性,然后看截图将你的本地protoc路径配置上就好了。
2.2)验证路径配置 输入 protoc --version
2.3) 将.proto消息协议文件转成.java文件
命令行格式:
protoc -I=proto所在的文件地址 --java_out=数据的java类的文件地址 要编译的proto文件名
编译common.proto 文件
protoc -I=D:\work\workspace\probuf-demo\src\main\java\com\lyh\protobuf\demo\protos --java_out=D:\work\workspace\probuf-demo\src\main\java common.proto
上面的指令的含义是:将D:\work\workspace\probuf-demo\src\main\java\com\lyh\protobuf\demo\protos下的common.proto 协议编译到 D:\work\workspace\probuf-demo\src\main\java 文件夹下,
如果该文件夹下没有对应的包路径,则自动创建。
编译brakingInfoReport.proto 文件
protoc -I=D:\work\workspace\probuf-demo\src\main\java\com\lyh\protobuf\demo\protos --java_out=D:\work\workspace\probuf-demo\src\main\java brakingInfoReport.proto
文件编译完了,我们看下怎么去使用吧
二.序列化和反序列化
测试样例如下:
@Test
public void testBrakingInfo() throws InvalidProtocolBufferException {
Common.ObjectMessageType objectMessageType = Common.ObjectMessageType.REPORT_BRAKING_INFO;
List<BrakingInfoReportProto.BrakingInfoReport.BrakingInfo> brakingInfoList = new ArrayList<>();
brakingInfoList.add(BrakingInfoReportProto.BrakingInfoReport.BrakingInfo.newBuilder()
.setBol(0.77F)
.setRts(System.currentTimeMillis())
.build());
brakingInfoList.add(BrakingInfoReportProto.BrakingInfoReport.BrakingInfo.newBuilder()
.setBol(0.88F)
.setRts(System.currentTimeMillis())
.build());
BrakingInfoReportProto.BrakingInfoReport report = BrakingInfoReportProto.BrakingInfoReport
.newBuilder()
.setJsonMessageType(Common.JsonMessageType.REPORT)
.setObjectMessageType(objectMessageType)
.setEt(ObjectMessageType.getObjectMessageTypeByIndex(objectMessageType.getNumber())==null?""
:ObjectMessageType.getObjectMessageTypeByIndex(objectMessageType.getNumber()).getValue())
.addData(BrakingInfoReportProto.BrakingInfoReport.BrakingInfo.newBuilder()
.setBol(0.55F)
.setRts(System.currentTimeMillis())
.build())
.addData(BrakingInfoReportProto.BrakingInfoReport.BrakingInfo.newBuilder()
.setBol(0.555F)
.setRts(System.currentTimeMillis())
.build())
.addData(BrakingInfoReportProto.BrakingInfoReport.BrakingInfo.newBuilder()
.setBol(0.66F)
.setRts(System.currentTimeMillis())
.build())
//还可以用这种方式加list
.addAllData(brakingInfoList)
.build();
System.out.println("序列化前:"+report);
//序列化对象,序列化之后的数组就是交互的数据报文
byte[] reportBytes = report.toByteArray();
//反序列化
BrakingInfoReportProto.BrakingInfoReport brakingInfoReport = BrakingInfoReportProto.BrakingInfoReport.parseFrom(reportBytes);
System.out.println("反序列化:"+brakingInfoReport);
}
https://github.com/leeahua/protobuf-demo.git对应的maven项目地址: