我们知道接口传输数据的格式有XML,它是 web services 使用的传输数据的格式,在web services 中叫 WSDL。
https://www.w3school.com.cn/wsdl/index.asp
不过 web Services 已经是被淘汰的技术了。
现在更是主流的是使用JSON作为数据传输格式。HTTP + JSON是黄金搭档。
什么是protocol buffer
protocol buffer是一种与语言和平台无关。
Protocol Buffer是用于结构化数据串行化的灵活、高效、自动的方法,有如XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。
protocol buffer 是如何使用
- 定义
xx.proto
文件,即 接口数据格式。 - 使用
proto
命令生成对应语言脚本。 - 通过语言脚本设置接口要发送/接收的数据。
定义 .proto 文件,
创建一个foo.proto
文件中定义你需要做串行化的数据结构信息。每个ProtocolBuffer信息是一小段逻辑记录,包含一系列的键值对。
这里定义一个简单的 foo.proto 文件定义了个人信息:
syntax = "proto2";
package info;
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;
}
这个信息就是你的接口要发送的数据格式。
文件说明:
syntax = "proto2";
文件最开始建议说明使用proto2还是proto3语法的声明。
package info;
文件必须以 package xxxx;
声明开头,作为协议唯一的标识,避免不同项目的命名冲突,你可以理解成我给一个人起名叫张三,如果要想找这个人,就要叫一声张三。
message Person {
...
message PhoneNumber {
...
}
}
一个 message
相当于一个指定类型的集合,例如 bool
, int32
, float
, double
,string
这些类型都是可以直接使用在proto协议中的某个message当中指定数据类型的。
一个message
可以直接嵌套另一个message
使用,被嵌套的message
就相当于string
一样,被认为是一种数据类型。
required string name=1;
required int32 id=2;
optional string email=3;
...
repeated PhoneNumber phone=4;
每个message
的字段必须要声明是required
,repeated
,optional
。
Required: 表示是一个必须字段,必须相对于发送方,在发送消息之前必须设置该字段的值,对于接收方,必须能够识别该字段的意思。发送之前没有设置required字段或者无法识别required字段都会引发编解码异常,导致消息被丢弃。
Optional:表示是一个可选字段,可选对于发送方,在发送消息时,可以有选择性的设置或者不设置该字段的值。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段,消息中的其它字段正常处理。因为optional字段的特性,很多接口在升级版本中都把后来添加的字段都统一的设置为optional字段,这样老的版本无需升级程序也可以正常的与新的软件进行通信,只不过新的字段无法识别而已,因为并不是每个节点都需要新的功能,因此可以做到按需升级和平滑过渡。
Repeated:表示该字段可以包含0~N个元素。其特性和optional一样,但是每一次可以包含多个值。可以看作是在传递一个数组的值。
好了,你现在对 .proto 文件的定义有了大概的一个了解了。
使用 proto 命令生成对应语言脚本
1、下载 protobuf 文件
https://github.com/protocolbuffers/protobuf/releases
以windows为例,下载下面两个文件:
- protobuf-python-3.12.3.zip
- protoc-3.12.3-win64.zip
2、 先解压 protobuf-python-3.12.3.zip 文件,得到 protobuf-3.12.3
目录,再解压 protoc-3.12.3-win64.zip 文件得到 protoc
目录,把你 protoc
目录放到 protobuf-3.12.3
目录。
图
3、 设置环境变量path
D:\pybase\protobuf-3.12.3\protoc\bin
将上面的路径添加环境变量。
4、 执行 proto
命令,生成python脚本。利用前面创建 foo.proto 文件。
protoc --python_out=. foo.proto
你会看到同目录下多出一个 foo_pb2.py
的文件。不用打开看了,反正你也看不懂。
通过语言脚本设置接口要发送/接收的数据
现在我们利用 foo_pb2.py
文件定义发送的接口数据。 创建一个test_foo_pb2.py
文件。
import foo_pb2
def set_info(info_):
info_.id = 1
info_.name = "tom"
info_.email = "tom@gmail.com"
phone = info_.PhoneNumber
phone.phone = 400100
phone.type = 2
return info_
info = foo_pb2.Person()
one_info = set_info(info)
print("设置数据:\n", one_info)
proto_info = one_info.SerializeToString()
print("序列化:\n", proto_info)
def get_info(wanted_info):
"""
反序列化的数据
"""
print("反序列化:\n")
wanted_id = wanted_info.id
print("info id:", wanted_id)
print("his age: ", wanted_info.name)
print("his phone number :", wanted_info.PhoneNumber.phone)
print("his phone type :", wanted_info.PhoneNumber.type)
first_parsed = foo_pb2.Person()
first_parsed.ParseFromString(proto_info)
get_info(first_parsed)
打印结果:
设置数据:
name: "tom"
id: 1
email: "tom@gmail.com"
序列化:
b'\n\x03tom\x10\x01\x1a\rtom@gmail.com'
反序列化:
info id: 1
his age: tom
his phone number : 400100
his phone type : 2
我帮你问:这有什么用?
想想当你在发送数据的时候,以 序列化的数据发送,是不是更节省资源?是不是更安全?