protobuf的使用
protobuf 和 json/xml 的区别#
Protocol Buffer 和 XML、JSON 一样都是结构数据序列化的工具,但它们的数据格式有比较大的区别:
首先,Protocol Buffer 序列化之后得到的数据不是可读的字符串,而是二进制流
其次,XML 和 JSON 格式的数据信息都包含在了序列化之后的数据中,不需要任何其它信息就能还原序列化之后的数据;但使用 Protocol Buffer 需要事先定义数据的格式 (.proto 协议文件),还原一个序列化之后的数据需要使用到这个定义好的数据格式
最后,在传输数据量较大的需求场景下,Protocol Buffer 比 XML、JSON 更小(3 到 10 倍)、更快(20 到 100 倍)、使用 & 维护更简单;而且 Protocol Buffer 可以跨平台、跨语音使用。
protobuf 使用过程#
1. 通过 Protocol Buffer 语法描述需要存储的数据结构,就是我们编写的.proto 文件
2. 过 Protocol Buffer 编译器编译 .proto 文件。将 .proto 文件 转换成对应平台(python、C++、Java)的代码文件
在终端输入下列命令进行编译#
protoc -I=$SRC_DIR --xxx_out=$DST_DIR $SRC_DIR/addressbook.proto
# 参数说明
# 1. $SRC_DIR:指定需要编译的.proto文件目录 (如没有提供则使用当前目录)
# 2. --xxx_out:xxx根据需要生成代码的类型进行设置
"""
对于 Java ,xxx = java ,即 -- java_out
对于 C++ ,xxx = cpp ,即 --cpp_out
"""
# 3. $DST_DIR :编译后代码生成的目录 (通常设置与$SRC_DIR相同)
# 4. 最后的路径参数:需要编译的.proto 文件的具体路径
# 编译通过后,Protoco Buffer会根据不同平台生成对应的代码文件
go 使用 protobuf#
1. 下载 protobuf 的编译器 protoc,github.com/protocolbuffers/protobu...,根据不同系统安装对应版本,然后把 bin 目录写到环境变量中,执行 protoc –version 成功说明安装成功
>libprotoc 3.17.1
2. 获取 protobuf 的编译器插件 protoc-gen-go,其他语言使用其他插件
这个仓库官方准备废弃,使用新
go get -u github.com/golang/protobuf/protoc-gen-go
3. 编写 proto 文件,例如 hello.proto
syntax = "proto3";
package proto;
option go_package ="./proto";
service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string greeting = 1;
}
4. 编译.proto 文件,发现生成 greeter.pb.go 文件
protoc --go_out=. proto/greeter.proto
protoc 编译器原理#
protoc 编译器是通过插件机制实现对不同语言的支持,比如 protoc 命令出现 --xxx_out
格式的参数,那么 protoc 将首先查询是否有内置的 xxx 插件,如果没有内置的 xxx 插件那么将继续查询当前系统中是否存在 protoc-gen-xxx 命名的可执行程序,最终通过查询到的插件生成代码。所以我们使用–go_out, 表示使用 protoc-gen-go 可执行程序。
如果我们新写了一个 protoc-gen-go-my 命令,并且注册插件 netrpc, 则可以使用命令 –go-my_out=plugins=netrpc。
protoc-gen-go
而这个可执行文件里面又实现了一层静态插件系统,比如 protoc-gen-go 内置了一个 gRPC 插件,用户可以通过 --go_out=plugins=grpc
参数来生成 gRPC 相关代码,否则只会针对 message 生成相关代码。
自定义插件#
我们可以模仿 protoc-gen-go,自定义一个插件。
先看看 protoc-gen-go 源码的 main 函数 (旧版本),所以只要往 generator 注册自定义的插件对象即可,不用修改这个 main 函数
package main
import (
"io/ioutil"
"os"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/generator" //我们新写的plugin会注册到这里
)
func main() {
g := generator.New()
data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
g.Error(err, "reading input")
}
if err := proto.Unmarshal(data, g.Request); err != nil {
g.Error(err, "parsing input proto")
}
...
}
自定义 plugin 对象,plugins/netrpc.go
generator 会处理 proto 文件,生成 generator.FileDescriptor 对象保存里面的信息。
package plugins
import (
"github.com/golang/protobuf/protoc-gen-go/generator"
"google.golang.org/protobuf/types/descriptorpb"
)
//自定义protoc-gen-go插件,通过--go_out=plugins=netrpc 来生成go代码
type NetrpcPlugin struct {
*generator.Generator
}
func init() {
//注册到generator
generator.RegisterPlugin(new(NetrpcPlugin))
}
func (p *NetrpcPlugin) Name() string {
return "netrpc"
}
func (p *NetrpcPlugin) Init(g *generator.Generator) {
p.Generator = g
}
func (p *NetrpcPlugin) GenerateImports(file *generator.FileDescriptor) {
if len(file.Service) > 0 {
p.genImportCode(file)
}
}
func (p *NetrpcPlugin) Generate(file *generator.FileDescriptor) {
for _, svc := range file.Service { //处理proto文件定义的service
p.genServiceCode(svc)
}
}
func (p *NetrpcPlugin) genImportCode(file *generator.FileDescriptor) {
p.P("// TODO: import code")
}
func (p *NetrpcPlugin) genServiceCode(svc *descriptorpb.ServiceDescriptorProto) {
p.P("// TODO: service code, Name = " + svc.GetName())
}
编译自定义插件生成可执行文件 protoc-gen-go-netrpc
go build -o protoc-gen-go-netrpc
cp protoc-gen-go-netrpc /home/csx/go/bin #把生成的可执行文件复制到gopath/bin目录
使用自定义的可执行文件来处理 hello.proto
protoc --go-netrpc_out=plugins=netrpc:. hello.proto
使用 go-micro 插件编译 protobuf#
该命令会在 bin 目录下生成 protoc-gen-micro (.exe),protoc 编译器利用 protoc-gen-micro 插件将.proto 文件转换为 micro 代码风格文件
go get github.com/micro/protoc-gen-micro/v2
2. 编译.proto 文件,会生成 greeter.pb.go, greeter.pb.mico.go
protoc --proto_path=. --micro_out=. --go_out=. proto/greeter.proto
grpc-gateway 框架编译 protobuf#
两个命令会在 $GOPATH/bin 目录下生成 protoc-gen-go,protoc-gen-grpc-gateway
$GOPATH 默认是 cd ~/go
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
protoc-gen-go 使用新仓库#
github.com/golang/protobuf 已经准备作废
使用新的库
google.golang.org/protobuf
安装 go 插件
The compiler plugin protoc-gen-go
will be installed in $GOBIN
, defaulting to $GOPATH/bin
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
protoc --go_out=. hello.proto
grpc 使用#
新 protoc-gen-go 命令不再支持 plugin 参数,需要重新下载 protoc-gen-go-grpc 命令
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
protoc --go_out=. hello.proto #编译message得到变量
protoc --go-grpc_out=. hello.proto #编译其他数据,依赖message变量
需要生成两个文件,hello.pb.go, hello_grpc.pb.go. 合并为一条语句
protoc –go_out=. –go-grpc_out=. hello.proto
protobuf3 语法#
www.cnblogs.com/tohxyblog/p/897476...
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: