protobuf学习
下载Protobuf
下载地址:https://github.com/protocolbuffers/protobuf/releases
Python安装Protobuf
在python中使用protobuf,还需要安装python对应的protobuf包(否则会报错:No module named goofgle):
pip install protobuf==3.12.0
proto文件语法
message Person{
required string name = 1;
message Info{
required int32 id = 1;
repeated string phonenumber = 2;
}
repeated Info info = 2;
}
此外,从上面proto文件中也可以发现,message中不同属性可以有不同的限定修饰符,有3种:
-
required:发送方发送的数据中必须包含这个字段的值,接收方接收的数据也必须要能识别该字段,大白话,加上required修饰符,这个字段双方必须使用,否则报错。
-
optional:可选字段,发送方可选择性地发送该字段,接收方如果能够识别该字段就进行相应解码处理,如果不能识别,则直接忽略。
-
repeated:可重复字段,发送方每次发送都可以包含多个值,类似于传递一个数组。
在日常使用protobuf时,有两个常见的tips:
1.分配标识号一般会按业务划分,不同业务间字段不按大小顺序紧密排序,如:
message data {
optional string name = 10001;
optional int32 age = 10002;
optional string job = 20001;
optional string hobby = 20002;
}
上述proto,基础信息(name、age)以1000开头,其他信息(job、hobby)以2000开头,这样后续要添加时,更加清晰,比如要添加性别这个基本信息 :optional string sex = 10003;。
.proto type | notes | C ++ type | Java type | Python type [2] | Type | Ruby type | C# type | PHP type |
---|---|---|---|---|---|---|---|---|
double | ||||||||
double | double | float | float64 | float | double | float | ||
float | ||||||||
float | float | float | FLOAT32 | float | float | float | ||
INT32 | 使用可变长度编码。编码负数的效率低 - 如果您的字段可能有负值,请改用sint32。 | INT32 | INT | INT | INT32 | Fixnum or Bignum (as needed) | INT | Integer |
Int64 | 使用可变长度编码。编码负数的效率低 - 如果您的字段可能有负值,请改用sint64。 | Int64 | long | int / long [3] | Int64 | TWINS | long | Integer/string[5] |
UINT32 | 使用可变长度编码。 | UINT32 | int [1] | int / long [3] | UINT32 | Fixnum or Bignum (as needed) | UINT | Integer |
UINT64 | 使用可变长度编码。 | UINT64 | Long [1] | int / long [3] | UINT64 | TWINS | ULONG | Integer/string[5] |
SINT32 | 使用可变长度编码。签名的int值。这些比常规int32更有效地编码负数。 | INT32 | INT | INT | INT32 | Fixnum or Bignum (as needed) | INT | Integer |
sint64 | 使用可变长度编码。签名的int值。这些比常规int64更有效地编码负数。 | Int64 | long | int / long [3] | Int64 | TWINS | long | Integer/string[5] |
fixed32 | 总是四个字节。如果值通常大于2 28,则比uint32更有效。 | UINT32 | int [1] | int / long [3] | UINT32 | Fixnum or Bignum (as needed) | UINT | Integer |
fixed64 | 总是八个字节。如果值通常大于2 56,则比uint64更有效。 | UINT64 | Long [1] | int / long [3] | UINT64 | TWINS | ULONG | Integer/string[5] |
sfixed32 | 总是四个字节。 | INT32 | INT | INT | INT32 | Fixnum or Bignum (as needed) | INT | Integer |
sfixed64 | 总是八个字节。 | Int64 | long | int / long [3] | Int64 | TWINS | long | Integer/string[5] |
Boolean | ||||||||
Boolean | Boolean | Boolean | Boolean | TrueClass / FalseClass | Boolean | Boolean | ||
string | 字符串必须始终包含UTF-8编码或7位ASCII文本。 | string | string | str / unicode[4] | string | String (UTF-8) | string | string |
byte | 可以包含任意字节序列。 | string | Byte string | Strait | []byte | String (ASCII-8BIT) | Byte string | string |
编译proto文件
& "C:\Users\admin\Downloads\protoc-21.1-win64\bin\protoc.exe" --python_out=. demo.proto
在Python中的基本使用
我们定义一个简单的proto文件,名为demo.proto,内容如下:
syntax = "proto3";
message Person {
string name = 1;
int32 age = 2;
}
通过protoc将demo.proto编译成Python文件,命令如下(protoc路径替换成自己的路径则可):
& "C:\Users\admin\Downloads\protoc-21.1-win64\bin\protoc.exe" --python_out=. demo.proto
--python_out用于指定生成Python文件要存放的路径,随后紧接demo.proto文件路径(注意有空格做间隔)。
运行命令后,会生成名为demo_pd2.py的文件。
然后我们导入demo_pd2文件,使用其中的Person类便可以实现Protobuf的编码与解码。
通过一段简单的代码演示一下:
# 导入proto
from demo_pb2 import Person
# 构造消息实体
p = Person()
p.name = "zhu"
p.age = 20
# 将实体转换成二进制
sp = p.SerializeToString()
print(sp)
# 构造消息实体
p2 = Person()
# 将二进制数据转换成实体
p2.ParseFromString(sp)
print(p2)
上述代码中,需要注意的是,ParseFromString函数不会直接返回解析后的结果,而是将结果直接填充到调用它的parse_person对象中。
blackboxprotobuf
blackboxprotobuf可以不用提前编写proto文件来解码出proto的结构
https://github.com/nccgroup/blackboxprotobuf
pip install blackboxprotobuf
复制十六进制到代码中
import blackboxprotobuf,base64
print(blackboxprotobuf.decode_message(base64.b64decode('base64内容')))