前言
Protobuf是google推出的一种数据协议,Protobuf(Google Protocol Buffers)。它具有高效的协议数据交换格式工具库(类似Json),它支持多语言(java、python、C++等等)、多平台(linux、win、mac等等)。
Protobuf简称proto,当前主要有proto2、proto3两个版本。本文主要介绍使用Python语言开发Protobuf2。
目录
四、定义 Protobuf、生成pb2.py文件、使用Protobuf
一、Protobuf特点
- 性能好/效率高: Protobuf传输效率快;相比于Json,Protobuf的时间效率和空间效率都比JSON强。
- 格式扩展兼容:使用旧的proto协议编码仍然可以读取使用了新协议编码的数据,更新的新协议也可以兼容之前proto的定义。
- 规范设计: Protobuf要求使用显式标识符和类型来规范消息。
二、安装Protobuf
使用pip安装Protobuf,执行如下命令即可:(简单方便,推荐)
pip install protobuf
查看版本:pip list | grep -i protobuf
三、安装编译工具
我们使用grpico-tools 软件包,生成服务器和客户端的接口代码,即生成 pb2.py 和 pb2_grpc.py 文件
pip install grpcio-tools
四、定义 Protobuf、生成pb2.py文件、使用Protobuf
1、我们首先定义一个 Protobuf,即:xxx.proto 文件,例如名为personal.proto
syntax = "proto2";
package tutorial;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}
- syntax = "proto2"; 是申明使用proto2版本。
在.proto
文件说明使用proto2还是proto3语法的声明:syntax = "proto2";
,如果不声明默认使用proto2的语法。 - package tutorial 为了避免不同项目的命名冲突,
.proto
文件以package xxxx;
声明开头,作为协议唯一的标识。 - message 是信息主体,类似一个结构体,里面能存放不同类型的数据;Person 是这个结构体的名称。比如:定义字符串——string,定义整型——int32,当然还有其他类型啦,后面再介绍。
- required 是指使用这个结构体时一定需要的,需要给它赋值。optional 是可选的意思,可以选择用,也可以不用,不强制。在personal.proto 中需要给name、id 赋值,emailke可赋可不赋。
2、然后使用使用grpico-tools 生成pb2.py文件,即:生成personal_pb2.py文件
python -m grpc_tools.protoc -I ./ --python_out=./ personal.proto
备注:-I ./ 表示
输入xxx.proto 文件所在的路经;./ 表示在当前目录。
--python_out=./ 表示输出的
pb2.py文件放在那里;./ 表示在当前目录
。personal.proto 是要编译的文件名称。
3、最后我们使用Protobuf,即调用生成的personal_pb2.py文件
# -*- coding: utf-8 -*-
import personal_pb2
def run():
data = personal_pb2.Person()
data.name = 'guopu'
data.id = 202103
data.email = '12345678@qq.com'
print(data)
if __name__ == '__main__':
run()
运行结果:
.proto
文件将编译后的以_pb.py
结尾的文件,可以认为是普通的python脚本这样用的。
五、常用定义proto的语法
5.1 定义package
为了避免不同项目的命名冲突,.proto
文件以package xxxx;
声明开头,作为协议唯一的标识。
5.2 定义message
Message的嵌套使用可以嵌套定义,也可以采用先定义再使用的方式。
Message的定义末尾可以不加“;”,也可以末尾加上“;”这两种方式都兼容。
向.proto文件添加注释,可以使用双斜杠(//) 语法格式。
5.3 定义属性
属性定义分为四部分:标注+类型+属性名+属性顺序号+[默认值],其示意如下所示。
标注 | 类型 | 属性名 | 属性顺序号 | [默认值] |
required | string | name | = 1 | [default=””]; |
下面分别对标注、类型和属性顺序号加以详细介绍。
标注包括“required”、“optional”、“repeated”三种,其中
required表示该属性为必选属性,否则对应的message“未初始化”,debug模式下导致断言,release模式下解析失败;
optional表示该属性为可选属性,不指定,使用默认值(int或者char数据类型默认为0,string默认为空,bool默认为false,嵌套message默认为构造,枚举则为第一个)
repeated表示该属性为重复字段,可看作是动态数组,类似于C++中的vector。
如果为optional属性,发送端没有包含该属性,则接收端在解析式采用默认值。对于默认值,如果已设置默认值,则采用默认值,如果未设置,则类型特定的默认值为使用,例如string的默认值为””。
Protobuf的属性基本属性类型如下:
protobuf属性 | Python属性 | 备注 |
double | double | 固定8个字节 |
float | float | 固定4个字节 |
int32 | int32 | 使用变长编码,对于负数编码效率较低,如果经常使用负数,建议使用sint32 |
int64 | int64 | 使用变长编码,对于负数编码效率较低,如果经常使用负数,建议使用sint64 |
uint32 | uint32 | 使用变长编码 |
uint64 | uint64 | 使用变长编码 |
sint32 | int32 | 采用zigzag压缩,对负数编码效率比int32高 |
sint64 | int64 | 采用zigzag压缩,对负数编码效率比int64高 |
fixed32 | uint32 | 总是4字节,如果数据>2^28,编码效率高于unit32 |
fixed64 | uint64 | 总是8字节,如果数据>2^56,编码效率高于unit32 |
sfixed32 | int32 | 总是4字节 |
sfixed64 | int64 | 总是8字节 |
bool | bool |
|
string | string | 一个字符串必须是utf-8编码或者7-bit的ascii编码的文本 |
bytes | string | 可能包含任意顺序的字节数据 |
属性顺序号是protobuf为了提高数据的压缩和可选性等功能定义的,需要按照顺序进行定义,且不允许有重复。
花絮
1)安装Protobuf,并查看版本
2)安装grpico-tools 编译工具
3)personal.proto 编译生成personal_pb2.py
personal_pb2.py的部分内容:
4)复杂版本的personal.proto
syntax = "proto2";
package tutorial;
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;
}
message AddressBook {
repeated Person person = 1;
}
希望对你有帮助~