天天看点

数据传输 之 PB协议(protocol buffer)是什么?怎么写?如何编译?

数据传输 之 PB协议(protocol buffer)是什么?怎么写?如何编译?

文章目录

    • 概念性的东西
      • 什么是PB协议?
      • PB支持语言
      • 给出官网
    • 如何写一个PB文件
      • Protobuf消息定义
        • ①限定修饰符
        • ②数据类型速查
        • ④字段编码值
        • ⑤默认值。
      • 几个注意事项
        • import
        • 关于package
        • 关于enum
    • 编译PB
      • 可编译文件
      • 放置位置
      • 开始编译
      • 阅览文件

概念性的东西

什么是PB协议?

ProtocolBuffer是用于序列化结构数据的灵活、高效、自动的方法,有如XML,不过它更小、更快、也更简单。一旦定义了你自己的数据结构,然后就可以使用特殊生成的源代码轻松的在各种数据流和使用的各种高级语言之间读写你的结构化数据。你甚至可以在不破坏根据“旧”格式编译的已部署程序的情况下更新你的数据结构。

PB支持语言

Protocol buffers currently support generated code in Java, Python, Objective-C, and C++. With our new proto3 language version, you can also work with Go, Ruby, and C#, with more languages to come.

给出官网

官网在此,能力够的朋友可以自行访问,英语能力一般的还是跟着我吧。

数据传输 之 PB协议(protocol buffer)是什么?怎么写?如何编译?

下载的话,自行点击进去,在“How do I start?”板块下有下载链接。

往下再拉,也有下载链接。不过能不能打得开,就看运气了,我开了四五次才加载出来。。。

如何写一个PB文件

Protobuf消息定义

你首先需要在一个 .proto 文件中定义你需要做串行化的数据结构信息。每个ProtocolBuffer信息是一小段逻辑记录,包含一系列的键值对。

消息由至少一个字段组合而成,类似于C语言中的结构。每个字段都有一定的格式。

字段格式:限定修饰符① | 数据类型② | 字段名称③ | = | 字段编码值④ | [字段默认值⑤]           

复制

这里有个非常简单的 .proto 文件定义了个人信息:

message Person {

required string name=1;
required int32 id=2;
optional string email=3;

enum PhoneType {
    MOBILE=0;
    HOME=1;
    WORK=2;
}

message PhoneNumber {
    required string number=1;
    optional PhoneType type=2 [default=HOME];
}

repeated PhoneNumber phone=4;
}           

复制

①限定修饰符

Required: 表示是一个必须字段,必须相对于发送方,在发送消息之前必须设置该字段的值,对于接收方,必须能够识别该字段的意思。发送之前没有设置required字段或者无法识别required字段都会引发编解码异常,导致消息被丢弃。

Optional:表示是一个可选字段,可选对于发送方,在发送消息时,可以有选择性的设置或者不设置该字段的值。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段,消息中的其它字段正常处理。—因为optional字段的特性,很多接口在升级版本中都把后来添加的字段都统一的设置为optional字段,这样老的版本无需升级程序也可以正常的与新的软件进行通信,只不过新的字段无法识别而已,因为并不是每个节点都需要新的功能,因此可以做到按需升级和平滑过渡。

Repeated:表示该字段可以包含0~N个元素。其特性和optional一样,但是每一次可以包含多个值。可以看作是在传递一个数组的值。

②数据类型速查

Protobuf定义了一套基本数据类型。几乎都可以映射到C++\Java等语言的基础数据类型.

数据传输 之 PB协议(protocol buffer)是什么?怎么写?如何编译?
  1. N 表示打包的字节并不是固定。而是根据数据的大小或者长度。
  2. 关于message,类似于C语言中的结构包含另外一个结构作为数据成员一样。
  3. 关于 fixed32 和int32的区别。fixed32的打包效率比int32的效率高,但是使用的空间一般比int32多。因此一个属于时间效率高,一个属于空间效率高。根据项目的实际情况,一般选择fixed32,如果遇到对传输数据量要求比较苛刻的环境,可以选择int32.

④字段编码值

编码值的取值范围为 1~2^32(4294967296)。

不信往上面翻翻看,看看是不是都是数值。

其中 1~15的编码时间和空间效率都是最高的,编码值越大,其编码的时间和空间效率就越低(相对于1-15),当然一般情况下相邻的2个值编码效率的是相同的,除非2个值恰好实在4字节,12字节,20字节等的临界区。比如15和16.

1900~2000编码值为Google protobuf 系统内部保留值,建议不要在自己的项目中使用。

protobuf 还建议把经常要传递的值把其字段编码设置为1-15之间的值。

消息中的字段的编码值无需连续,只要是合法的,并且不能在同一个消息中有字段包含相同的编码值。

⑤默认值。

当在传递数据时,对于required数据类型,如果用户没有设置值,则使用默认值传递到对端。当接受数据是,对于optional字段,如果没有接收到optional字段,则设置为默认值。

几个注意事项

import

protobuf 接口文件可以像C语言的h文件一样,分离为多个,在需要的时候通过 import导入需要的文件。

虽然可以在单个.proto文件中定义多种消息类型(例如消息,枚举和服务),但当在单个文件中定义大量具有不同依赖性的消息时,也

可能导致依赖性膨胀。建议每个.proto文件包含尽可能少的消息类型。

关于package

避免名称冲突,可以给每个文件指定一个package名称,对于C++解析为名称空间。

记得在开头加上这两句:

syntax = "proto3";

package demo;           

复制

关于enum

枚举的定义和C++相同,但是有一些限制。

  1. 枚举值必须大于等于0的整数。
  2. 使用分号(;)分隔枚举变量而不是C++语言中的逗号(,)

编译PB

可编译文件

首先,你要有一个PB文件可以拿去编译,我知道你多半也没有,没事我这里有。

syntax = "proto3";
 
package demo;
message Person {
    string name = 1;
    int32 id = 2;
    string email = 3;
 
    enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }
 
    message PhoneNumber {
        string number = 1;
        PhoneType type = 2;
    }
    repeated PhoneNumber phone = 4;
}           

复制

放置位置

爱放哪儿放哪儿,我放在了下载文件的同目录下。

数据传输 之 PB协议(protocol buffer)是什么?怎么写?如何编译?

开始编译

我下载了好多款,不过主语言是C++,毕竟打开一次不容易。打不开下载目录的小伙伴可以私信我拿。

打开cmd, cd到该目录,protoc.exe的命令行参数格式如下:

protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR path/to/file.proto           

复制

数据传输 之 PB协议(protocol buffer)是什么?怎么写?如何编译?

编译之后就会出现新的文件了。

阅览文件

打开之后太长了,自己去看。我这里提几点。

(1)proto中的package在C++中是namespace;

(2)proto中的message在C++中是class,类里面有各个成员的set/get;基类是google::protobuf::Message。

(3)代码中可以看见C++11中的移动构造和移动赋值函数。           

复制

至于API啊,实际操作的时候再说吧。