简介
在上一篇文章中,我们已经了解了protobuf
是什么,还有proto
文件该如何编写
在本文中,将着重讲讲protobuf
该怎么用
Protobuf使用教程
Protobuf是一种高效数据序列化协议,可支持多种编程语言,不同编程语言使用方法或略有差异、或有多种方法,以下主要介绍大致的、通用的使用方法
安装编译器
使用protobuf
前,需先安装其编译器—protoc
(下载地址可看文末)
进入项目下载界面,根据自己的系统选择下载合适的版本,如喜欢也可下载源码自行构建
接着将其解压目录中的bin
目录配置到系统环境变量内,方便全局使用
配置成功后,可以在命令行窗口(win+R
调出)输入protoc --version
查看protoc
版本,验证是否配置成功
编译Proto
.proto
文件并不能直接使用,我们需要将其编译成对应编程语言的序列化工具代码,从而进行使用
这一步,我们需要使用上方安装的protoc
对.proto
文件进行编译,protoc
是一个命令行工具,主要使用步骤就是在命令行中通过命令调用protoc
对目标进行编译
具体protoc
的命令,可在命令行中,通过protoc --help
命令,获取其部分命令解释,主要关注如下内容:
-IPATH, --proto_path=PATH 指定搜索目录
--cpp_out=OUT_DIR 生成 C++ 源码
--csharp_out=OUT_DIR 生成 C# 源码
--java_out=OUT_DIR 生成 Java 源码
--kotlin_out=OUT_DIR 生成 Kotlin 源码
--objc_out=OUT_DIR 生成 Objective-C 源码
--php_out=OUT_DIR 生成 PHP 源码
--pyi_out=OUT_DIR 生成 python 源码
--python_out=OUT_DIR 生成 Python 源码
--ruby_out=OUT_DIR 生成 Ruby 源码
--rust_out=OUT_DIR 生成 Rust 源码
-IPATH
或--proto_path
可简写为-I
,等号后接一个路径,表示模块搜索路径,可以有多个- 当你的
.proto
文件比较庞大,并且在里面有import
导入其它proto
文件,此时就可以用该命令指定导入文件所在目录,告诉编译器该去哪搜索这些文件
- 当你的
--**_out
形式的命令参数表示需要生成的目标语言源码,等号后接一个路径,表示生成文件保存的目录,**
表示支持生成的编程语言
举个例子
假设我们有个名为
example.proto
的结构文件,大致如下:syntax = "proto3"; message Student { string id = 1; string name = 2; int32 sex = 3; int32 age = 4; string address = 5; }
在当前目录打开命令行,输入如下命令:
protoc --python_out=. example.proto
- 命令表示将
example.proto
编译为python
代码,输出目录为.
(即当前目录)命令运行完成后,会在当前目录生成一个
example_pb2.py
的文件,我们可在python
程序内使用它对我们的消息进行序列化和反序列化再举个例子
我们运行
protoc --version
后,可以看到命令参数里支持生成的语言并没有js
,如果我们想生成js
文件怎么办首先,
protoc
是可以生成js
代码的,之所以前面的不支持,是由于一些高版本的protoc
把部分编程语言的支持分化出来,单独作为插件存在,需要可自行安装搭配
- 可以降低
protoc
的版本,一些较低的版本是支持--js_out
的(高版本将其分化出来成插件了)- 如果不想降低版本
- 如果有
npm
,可全局安装protoc-gen-js
- 如果无
npm
,可以到protobuf-javascript
项目地址手动下载js
的编译器包并解压到本地,然后通过--plugin
指定插件名及插件路径使用;如不想使用--plugin
指定,也可直接将解压内容整个拖前面protoc
的目录下- 也可以使用一些第三方工具,如
protobufjs-cli
、protobufjs
解决
js
支持后,即可使用下列代码生成js
版本的序列化库protoc --js_out=import_style=commonjs,binary:. example.proto
- 上面的命令会将
example.proto
编译为js
内可用的序列化工具代码,风格为commonjs
(即使用require
导入)注意:目前尚未实现对
ES6
样式导入的支持。可以通过使用Browserify、webpack、Closure Compiler 或类似工具来进一步解析以支持浏览器
开始使用
生成好目标环境的编译文件后,我们即可在项目内使用protobuf
来提高我们的消息传输效率
Python示例
大致代码如下:
# 从编译文件导入对应消息类
from example_pb2 import Student
# 实例化消息类
stu = Student()
# 填充数据
stu.id = "18934305"
stu.name = "路人甲"
stu.sex = 1
stu.age = 18
stu.address = "斗气大陆萧家老宅"
# 序列化为二进制数据
data = stu.SerializeToString()
# 实例化新对象
newStu = Student()
# 将二进制数据解析到新对象
newStu.ParseFromString(data)
# 输出
print(f"序列化后数据:\n{data}")
print(f"反序列化后数据:\n{newStu}")
- 其中,
example_pb2
为之前example.proto
编译后的产物 - 经过测试,上面的数据
stu
序列化后的二进制数据大小大概为84
字节,而相同数据的json
格式大小为210
字节
在使用上方生成的example_pb2
时,我们会发现,生成的代码基本不可读,使用过程代码也没有丝毫智能提示,需要自己参照proto
文件才知道需导入该Student
,而具体的序列化函数还得看使用文档
我们打开example_pb2.py
文件,如下:
- 不难看出,代码可读性是比较差的
通过官方的protoc
生成的python
格式代码可读性是比较差的,可能比较适合一些保密需求高或小型项目,如果我们希望提高代码可读性,可以使用betterproto
生成代码
- 首先,需要安装
betterproto
,使用pip
安装
pip install betterproto
- 接着使用其重新编译
proto
文件
protoc --python_betterproto_out=. example.proto
-
命令运行成功后,会在当前目录生成一个
example.py
文件,内容大致如下: -
可以看出,代码可读性变好了很多,并且拥有更好的编写体验,大致使用代码如下:
# 从编译文件导入对应消息类
from example import Student
# 实例化消息类
stu = Student()
# 填充数据
stu.id = "18934305"
stu.name = "路人甲"
stu.sex = 1
stu.age = 18
stu.address = "斗气大陆萧家老宅"
# 序列化为二进制数据
data = bytes(stu)
# 实例化新对象
newStu = Student()
# 将二进制数据解析到新对象
newStu.parse(data)
Nodejs示例
大致代码如下:
// 导入编译文件
const proto = require('./example_pb');
// 实例化消息类
const stu = new proto.Student();
// 填充数据
stu.setId('18934305');
stu.setName('路人甲');
stu.setSex(1);
stu.setAge(18);
stu.setAddress('斗气大陆萧家老宅');
// 序列化为二进制数据
const data = stu.serializeBinary();
// 将二进制数据解析到新对象
const newStu = proto.Student.deserializeBinary(data);
// 输出
console.log(`序列化后数据:\n${data}`);
console.log(`反序列化后数据:\n${newStu}`);
以上主要举例了两种使用方法,更多的使用方法可自行探索
protoc下载地址:https://github.com/protocolbuffers/protobuf/releases
protoc编译js文档:https://protobuf.dev/protobuf-javascript/
protoc编译js插件下载地址:https://github.com/protocolbuffers/protobuf-javascript/releases
标签:protoc,一文,proto,--,stu,上手,序列化,out,protobuf From: https://www.cnblogs.com/skmcj/p/18467463