gRPC,由 google 开发的一种远程过程调用协议。gRPC 支持多种语言之间的调用,本文主要讲述 gRPC 基于 Go 的实现。
gRPC 简介
gRPC 使用 Protocol Buffer 作为其接口定义语言,使得 gRPC 客户端可以跨机器、跨语言调用 gRPC 服务器的方法。
Protocol Buffer 定义接口的输入参数和返回类型
gRPC 服务端:实现接口方法,并运行 gRPC Server
gRPC 客户端:调用 gRPC Stub (相当于 gRPC Server 在客户端的代理,拥有与 Server 实现的接口方法)的接口
环境安装
Mac 安装 go gRPC 所需环境
protobuf
安装 protobuf
1 | brew install protobuf |
检查安装是否成功
1 | ❯ protoc --version |
protoc-gen-go、protoc-gen-go-grpc
安装 protoc-gen-go、protoc-gen-go-grpc
1 | go install google.golang.org/protobuf/cmd/protoc-gen-go@latest |
1 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest |
安装完成后,可以在 ${GOPATH}/bin
下看到 protoc-gen-go
和 protoc-gen-go-grpc
确认 ${GOPATH}/bin
已添加到环境变量的 PATH 中
Protobuf
Protobuf 是 google 开发的序列化数据格式,定义交换的数据格式,序列化和反序列化数据到各种语言,实现跨语言、跨平台通信。
Protobuf 版本
.proto 文件的开头需要注明使用的 Protobuf 版本号,Protobuf 共有 editions、proto2、proto3 三种版本,建议使用 proto3,下面说明均以 proto3 为例。
1 | syntax = "proto3"; |
如不声明,默认使用 proto2。
数据类型
基础类型
Protobuf 支持多种内置数据类型,并可以映射到各种语言,以 Go 语言为例:
Protobuf | Go数据类型 | 备注 |
---|---|---|
double | float64 | |
float | float32 | |
int32 | int32 | 负数会占用更多字节 |
int64 | int64 | |
uint32 | uint32 | 字节长度会依据数字大小变化 |
uint64 | uint64 | |
sint32 | int32 | 与 int32 同表示 32 位整数,但 sin32 更适合处理负数场景,正负数相同字节数 |
sint64 | int64 | |
fixed32 | uint32 | 与 uint32 同表示 32 位正整数,fixed32 在处理大于 $2^{28}$ 的数时更高效,永远是 4 字节 |
fixed64 | uint64 | |
sfixed32 | int32 | |
sfixed64 | int64 | |
bool | bool | |
string | string | |
bytes | []byte |
定义的 enum
和 message
也可作为数据类型。
repeated
用于描述数组,可重复各种基础类型,包括内置类型、 enum
和 message
1 | message Example { |
map
用于键值对结构,第一位为 key 类型,第二位 value 类型
1 | message Example { |
key 和 value 的类型可以是基础类型,包括内置类型、 enum
和 message
,但不能是 repeated
,如果希望 value 为数组,需要先用 message
包装这个 repeated
1 | message Class { |
enum
enum
枚举类型,类型名采用驼峰命名方式,字段命名采用大写字母加下划线分隔方式。
1 | // 定义一个 enum 类型 |
enum
的默认值为其 0 值,所以必须在第一位定义 0 值。
enum
可以通过添加 option allow_alias = true;
允许使用别名。
1 | enum EnumAllowingAlias { |
message
message
消息类型,类型名采用驼峰命名方式,字段命名采用小写字母加下划线分隔方式。
1 | message SearchRequest { |
每个字段都要分配唯一的数值标签 tag。已有序号不能随意改动,不然会导致调用失败,在后面添加新 tag 字段不影响旧有调用。
message
类型里支持嵌套其他 message
或 enum
定义.
1 | message SearchResponse { |
在 parent message 外也可以引用到嵌套的 message 类型.
1 | message SomeOtherMessage { |
service
定义远程调用方法作为客户端与服务端的约定,服务端需实现此接口,用户端调用此接口
1 | service SearchService { |
生成代码
编辑完 .proto 文件后,便可生成各种语言的代码,供客户端和服务端使用,以 Go 语言为例,生成代码命令如下:
一个简单的 gRPC
实现客户端向服务端查询用户的信息