protobuf 简要介绍及应用

官方文档: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 TypeNotesC++ TypeJava TypePython Type[2]Go TypeRuby TypeC# TypePHP TypeDart Type
double doubledoublefloatfloat64Floatdoublefloatdouble
float floatfloatfloatfloat32Floatfloatfloatdouble
int32Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.int32intintint32Fixnum or Bignum (as required)intintegerint
int64Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.int64longint/long[3]int64Bignumlonginteger/string[5]Int64
uint32Uses variable-length encoding.uint32int[1]int/long[3]uint32Fixnum or Bignum (as required)uintintegerint
uint64Uses variable-length encoding.uint64long[1]int/long[3]uint64Bignumulonginteger/string[5]Int64
sint32Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.int32intintint32Fixnum or Bignum (as required)intintegerint
sint64Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.int64longint/long[3]int64Bignumlonginteger/string[5]Int64
fixed32Always four bytes. More efficient than uint32 if values are often greater than 228.uint32int[1]int/long[3]uint32Fixnum or Bignum (as required)uintintegerint
fixed64Always eight bytes. More efficient than uint64 if values are often greater than 256.uint64long[1]int/long[3]uint64Bignumulonginteger/string[5]Int64
sfixed32Always four bytes.int32intintint32Fixnum or Bignum (as required)intintegerint
sfixed64Always eight bytes.int64longint/long[3]int64Bignumlonginteger/string[5]Int64
bool boolbooleanboolboolTrueClass/FalseClassboolbooleanbool
stringA string must always contain UTF-8 encoded or 7-bit ASCII text.stringStringstr/unicode[4]stringString (UTF-8)stringstringString
bytesMay contain any arbitrary sequence of bytes.stringByteStringstr[]byteString (ASCII-8BIT)ByteStringstring

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项目地址:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值