携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
简介
protobuf是一套类似XML或者JSON的数据传输格式和规范,它的作用是在不同的应用或者进程之间通信时作为传输数据,因此通信时传递的信息是需要严格按照Progobuf定义的message的数据结构进行打包,然后再编译成二进制的byte流进行传输或者存储。
优点:
- 结构化:使用起来相对简单,提供了完整详细的操作API;
- 轻量化:序列化后体积较小,比XML要小3-10倍;
- 高性能:解析速度快,比XML要快20~100倍;
- 高兼容:平台无关、语言无关,很好的支持向上和向下兼容;
缺点:
- 二进制格式可读性差;
- 自定义protobuf的工作量偏大;
- 缺乏自描述;
安装和使用
protoc安装
在gRPC开发中,我们尝尝需要与protobuf进行打交道,在编写了.proto文件后,我们会需要到一个编译器,那就是protoc,protoc是protobuf的编译器,使用c++所编写的,其主要功能是用于编译.proto文件。
macos安装步骤
1、首先使用Home Brew安装Protobuf
$ brew install protobuf
2、安装好后查看是否安装成功。
$ protoc --version
如图说明安装成功。
windows安装步骤
1、下载并解压压缩包,下载地址:github.com/protocolbuf…
2、查看bin下的protoc文件
3、将bin文件夹下protoc应用程序复制到Go\bin:
4、在命令行里输入protoc --version,查看结果:
protoc 插件安装
安装完protoc编译器后,针对不同的语言,还需要不同的运行时的protoc插件,那么go语言对应的插件就是protoc-gen-go插件,安装命令如下:
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.3.2
$ go install google.golang.org/grpc/cmd/protoc-gen-go@v1.2
后面的版本号可以根据自己的需要更改。
将所编译安装的 Protoc Plugin 的可执行文件中移动到相应的 bin 目录下,主要目的是将二进制文件 protoc-gen-go 移动到 bin 目录下,让其可以直接运行 protoc-gen-go 执行,例如:
$ mv $GOPATH/bin/protoc-gen-go /usr/local/go/bin/
编译和生成 proto 文件
创建proto文件
proto文件一般以.proto结尾,可以在一个.proto文件中定义一个或多个消息类型。
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
int64 role = 2;
}
message HelloReply {
string message = 1;
}
- syntax: 在最开头的
syntax描述的是版本信息,proto目前有两个版本proto2和proto3。syntax="proto3"明确的设置了语法格式为proto3,如果不设置syntax即默认为proto2。 - service: 定义名为
Greeter的RPC服务(Service),其包含RPC方法SayHello,入参为HelloRequest消息体(message),出参为HelloReply消息体。 - message: 定义消息体,每一个消息体的字段包含三个属性:类型、字段名称、字段编号。在消息体的定义上,除类型以外均不可重复。
- 字段编号: 消息类型中的每个字段都需要定义唯一的编号,该编号会用来识别二进制数据中的字段。编号在1-15范围内可以用一个字节编码表示,在16-2047范围用两个字节表示,所以将15以内得编号留给频繁出现的字段可以节省空阿金。
- 字段规则: 每个字段可以被
singular或者repeated修饰,如果不指定修饰类型,默认值为singular。
-
- singular:表示被修饰的字段最多出现一次,即出现0次或者1次。
- repeated:表示被修饰的字段可以出现任意次,包括0次。
- 枚举类型: 在定义消息的时候,希望字段的值只能是预期某些值中的一个,例如,现在为 HelloRequest 添加 role 字段,它的值只能是 1、2、3中的一个。可以非常简单的通过向消息定义中添加枚举,并为每个可能的枚举值添加常量来实现。如下:
message HelloRequest {
string name = 1;
enum role {
1 = 0;
2 = 1;
3 = 2;
}
Role role = 2;
}
- import导入其他proto: 在一个 .proto 文件中可以导入其他 .proto 文件,这样就可以使用它导入的 .proto 中定义的消息类型了。
import "xxx/xxx.proto"
- 嵌套消息: 消息类型可以定义在消息类型的内部,即嵌套定义,里面下面的 Result 类型定义在 SearchResponse 的内部。不单单是一层嵌套,也可以多层嵌套。
message HelloResponse {
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
repeated Result results = 1;
}
生成 proto 文件
接下来我们在项目的根目录下,执行 protoc 的相关命令来生成对应的 pb.go 文件,如下:
$ protoc --go_out=plugins=grpc:. ./proto/*.proto
- –go_out:设置所生成 Go 代码输出的目录,该指令会加载 protoc-gen-go 插件达到生成 Go 代码的目的,生成的文件以 .pb.go 为文件后缀,在这里 “:”(冒号)号充当分隔符的作用,后跟命令所需要的参数集,在这里代表着要将所生成的 Go 代码输出到所指向 protoc 编译的当前目录。
- plugins=plugin1+plugin2:指定要加载的子插件列表,我们定义的 proto 文件是涉及了 RPC 服务的,而默认是不会生成 RPC 代码的,因此需要在 go_out 中给出 plugins 参数传递给 protoc-gen-go,告诉编译器,请支持 RPC(这里指定了内置的 grpc 插件)。
在执行这条命令后,就会生成此 proto 文件的对应.pb.go 文件,如下:
helloworld.pb.go helloworld.proto