共计 4398 个字符,预计需要花费 11 分钟才能阅读完成。
protobuf 简介
Protocol Buffers(protobuf)
:与编程语言无关,与程序运行平台无关的 数据序列化协定 以及 接口定义语言(IDL: interface definition language)。
要应用 protobuf
须要先了解几个概念:
-
protobuf
编译器protoc
,用于编译.proto
文件- 开源地址:https://github.com/protocolbu…
- 编程语言的
protobuf
插件,搭配protoc
编译器,依据.proto
文件生成对应编程语言的代码。 protobuf runtime library
:每个编程语言有各自的protobuf runtime
,用于实现各自语言的protobuf
协定。-
Go 语言的
protobuf
插件和runtime library
有过 2 个版本:-
第 1 个版本开源地址:https://github.com/golang/protobuf,蕴含有插件
proto-gen-go
,能够生成xx.pb.go
和xx_grpc.pb.go
。Go 工程里导入该版本的protobuf runtime
的形式如下:import "github.com/golang/protobuf"
-
第 2 个版本开源地址:https://github.com/protocolbuffers/protobuf-go,同样蕴含有插件
proto-gen-go
。不过该项目标proto-gen-go
从v1.20
版本开始,不再反对生成 gRPC 服务定义,也就是xx_grpc.pb.go
文件。要生成 gRPC 服务定义须要应用grpc-go
里的progo-gen-go-grpc
插件。Go 工程里导入该版本的protobuf runtime
的形式如下:import "google.golang.org/protobuf"
举荐应用第 2 个版本,对 protobuf 的 API 做了优化和精简,并且把工程界线分分明了:
- 第一,把
protobuf
的 Go 实现都放在 protobuf 的我的项目里,而不是放在 golang 语言我的项目上面。 - 第二,把
gRPC
的生成,放在grpc-go
我的项目里,而不是和protobuf runtime
混在一起。
有的老我的项目可能应用了第 1 个版本的
protobuf runtime
,在老我的项目里开发新性能的时候也能够应用第 2 个版本protobuf runtime
,反对 2 个版本在一个 Go 我的项目里共存。然而要 留神:一个我的项目里同时应用 2 个版本必须保障第一个版本的版本号不低于v1.4
。 -
gRPC-Go 简介
gRPC-Go: gRPC 的 Go 语言实现,基于 HTTP/ 2 的 RPC 框架。
开源地址:https://github.com/grpc/grpc-go
Go 我的项目里导入该模块的形式如下:
import "google.golang.org/grpc"
grpc-go
我的项目里还蕴含有 protoc-gen-go-grpc
插件,用于依据 .proto
文件生成 xx_grpc.pb.go
文件。
环境装置
分为 3 步:
-
装置 Go
- 步骤参考:https://go.dev/doc/install
-
装置 Protobuf 编译器
protoc
: 用于编译.proto
文件- 步骤参考:https://grpc.io/docs/protoc-i…
-
执行如下命令查看
protoc
的版本号,确认版本号是 3 +,用于反对 protoc3protoc --version
-
装置
protoc
编译器的 Go 语言插件-
protoc-gen-go
插件:用于生成xx.pb.go
文件go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
-
protoc-gen-go-grpc
插件:用于生成xx_grpc.pb.go
文件go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
-
留神:有的教程可能只让你装置protoc-gen-go
,没有装置protoc-gen-go-grpc
,那有 2 种状况:
- 应用的是第 1 个版本
github.com/golang/protobuf
的protoc-gen-go
插件。 - 应用的是第 2 个版本
google.golang.org/protobuf
的protoc-gen-go
插件并且protoc-gen-go
版本号低于v1.20
。从v1.20
开始,第 2 个版本的protoc-gen-go
插件不再反对生成 gRPC 服务定义。上面是官网阐明:
The v1.20
protoc-gen-go
does not support generating gRPC service definitions. In the future, gRPC service generation will be supported by a newprotoc-gen-go-grpc
plugin provided by the Go gRPC project.The
github.com/golang/protobuf
version ofprotoc-gen-go
continues to support gRPC and will continue to do so for the foreseeable future.
官网示例
下载代码
以 grpc-go
的 v1.41.0 版本为例,下载代码并进入到 grpc-go/examples/helloworld
目录:
git clone -b v1.41.0 https://github.com/grpc/grpc-go
cd grpc-go/examples/helloworld
运行代码
-
启动服务端
go run greeter_server/main.go
终端会打印如下内容,示意服务端曾经启动并且在监听
50051
端口2022/01/02 13:01:08 server listening at [::]:50051
-
启动客户端。客户端会发送
SayHello
申请给服务端go run greeter_client/main.go
终端会打印如下内容,示意收到了服务端的响应。
2022/01/02 13:01:25 Greeting: Hello world
工程开发
本人在应用 protobuf
和grpc-go
开发的时候,依照如下步骤来操作:
- 定义
.proto
文件,包含音讯体和 rpc 服务接口定义 - 应用
protoc
命令来编译.proto
文件,用于生成xx.pb.go
和xx_grpc.pb.go
文件 - 在服务端实现 rpc 里定义的办法
- 客户端调用 rpc 办法,获取响应后果
咱们通过对下面的 grpc-go/examples/helloworld
做批改,来阐明上述步骤。
-
第一步,在
helloworld.proto
里减少一个 rpc 办法SayHelloAgain
,参数和返回值和SayHello
放弃一样。// The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} // send another greeting rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}}
-
第二步,在
grpc-go/examples/helloworld
目录应用protoc
命令编译.proto
文件,生成新的helloworld.pb.go
和helloword_grpc.pb.go
文件。命令如下:protoc --go_out=. --go_opt=paths=source_relative \ --go-grpc_out=. --go-grpc_opt=paths=source_relative \ helloworld/helloworld.proto
-
第三步,在服务端实现 rpc 里新定义的办法
SayHelloAgain
。在greeter_server/main.go
增加如下代码:func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {log.Printf("Received: %v", in.GetName()) return &pb.HelloReply{Message: "Hello again" + in.GetName()}, nil }
-
第四步,在客户端调用新定义的 rpc 办法,获取响应后果。在
greeter_client/main.go
增加如下代码:r2, err2 := c.SayHelloAgain(ctx, &pb.HelloRequest{Name: name}) if err2 != nil {log.Fatalf("could not greet: %v", err2) } log.Printf("Greeting: %s", r2.GetMessage())
-
第五步,运行程序
-
先启动服务端
go run greeter_server/main.go
-
再启动客户端
go run greeter_client/main.go Alice
-
客户端会打印如下内容:
2022/01/02 13:37:58 Greeting: Hello alice
2022/01/02 13:37:58 Greeting: Hello again alice
至此,咱们就对如何在 Go 工程里应用 protobuf
和gRPC
有了一个初步的理解和入门。
进阶学习
想要进一步学习,次要是深刻理解 protobuf
和gRPC
在 Go 语言里的应用技巧和原理
-
protobuf
官网学习地址:- https://developers.google.com…
- https://developers.google.com…
- https://developers.google.com…
- https://developers.google.com…
-
gRPC
官网学习地址:- https://grpc.io/docs/language…
开源地址
文章和示例代码开源地址在 GitHub: https://github.com/jincheng9/go-tutorial
公众号:coding 进阶
集体网站:https://jincheng9.github.io/
知乎:https://www.zhihu.com/people/thucuhkwuji
References
- https://grpc.io/docs/language…
- https://github.com/protocolbu…
- https://stackoverflow.com/que…
- https://github.com/golang/pro…
- https://github.com/protocolbu…