Go Protobuf使用和详解快速入门

2,409 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

简介

protobuf是一套类似XML或者JSON的数据传输格式和规范,它的作用是在不同的应用或者进程之间通信时作为传输数据,因此通信时传递的信息是需要严格按照Progobuf定义的message的数据结构进行打包,然后再编译成二进制的byte流进行传输或者存储。

优点:

  • 结构化:使用起来相对简单,提供了完整详细的操作API;
  • 轻量化:序列化后体积较小,比XML要小3-10倍;
  • 高性能:解析速度快,比XML要快20~100倍;
  • 高兼容:平台无关、语言无关,很好的支持向上和向下兼容;

缺点:

  • 二进制格式可读性差;
  • 自定义protobuf的工作量偏大;
  • 缺乏自描述;

安装和使用

protoc安装

gRPC开发中,我们尝尝需要与protobuf进行打交道,在编写了.proto文件后,我们会需要到一个编译器,那就是protocprotocprotobuf的编译器,使用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 目前有两个版本 proto2proto3syntax="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