Loading

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内容')))

在线工具:https://gchq.github.io/CyberChef/

posted @ 2023-06-17 15:45  流星Studio  阅读(114)  评论(0编辑  收藏  举报