GRPC (1) : 基本概念
Go gRPC 简介gRPC 是由 Google 开源的基于 HTTP/2 协议的开源远程过程调用(RPC)框架,使用 Protocol Buffers 序列化协议。相比于传统的 HTTP+JSON 的通信方式,gRPC 更轻量、更快速,拥有更多的优点。Go gRPC 安装
首先,你需要安装Go gRPC环境。可以打开你的终端,输入以下命令进行安装:
go get -u google.golang.org/grpc
安装完成后,你需要安装 Protocol Buffer 编译器。:
mac
brew install protobuf
CentOS
yum install -y protobuf protoc --version
Ubuntu
apt install -y protobuf-compiler protoc --version # Ensure compiler version is 3+
接下来,你需要安装 Go 的 Protocol Buffer 插件。可以使用以下命令安装:
//go get -u github.com/golang/protobuf/protoc-gen-go go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
Go gRPC 开发准备工作
一般来说,gRPC 包含服务端和客户端两部分。服务端主要包含 Proto 文件定义和服务实现;客户端主要包含服务调用和响应处理。
在开始之前,我们需要做一些准备工作:
定义 protobuf文件
首先,我们需要定义protobuf文件。protobuf是一种跨平台、语言无关的序列化协议,它能够将数据结构转换成二进制格式,以实现基于TCP、UDP等协议的跨服务通信, 通常以.proto结尾
protobuf 文件是 gRPC 的核心部分,用于描述服务所需要的数据类型、请求参数和服务方法等信息, 新建一个文件 example.proto
syntax = "proto3"; package example; message Message { string data = 1; } service Greeter { rpc SayHello (Message) returns (Message) {}; }
在该示例中,protobuf 文件定义了一个名为 example 的包,包含了一个名为 Message 的消息类型,以及一个名为 Greeter 的服务,该服务中包含了一个名为 SayHello 的方法。
生成go代码
接下来,我们将使用 protocol buffer 编译器 protoc 命令将刚刚新建的文件编译成 Go 代码。打开终端,输入以下命令:
$ protoc -I. --go_out=plugins=grpc:. ./example.proto
该命令将根据 example.proto 文件生成一个名为 example.pb.go 的 Go 代码文件,并将 grpc 标志作为参数传递,以支持 gRPC 功能。实现服务端
go_out详细解读
大家在使用时,遇到过这些写法:–go_out=paths=import:.、–go_out=paths=source_relative:.,或者–go_out=plugins=grpc:.。
--go_out参数是用来指定 protoc-gen-go 插件的工作方式和Go代码的生成位置,而上面的写法正是表明该插件的工作方式。 --go_out主要的两参数为plugins和paths,分别表示生成Go代码所使用的插件,以及生成的Go代码的位置。 --go_out的写法是,参数之间用逗号隔开,最后加上冒号来指定代码的生成位置,比如--go_out=plugins=grpc,paths=import:.。
paths参数有两个选项,imports和 source_relative, 默认为 import,表示按照生成的Go代码的包的全路径去创建目录层级,source_relative 表示按照 proto源文件的目录层级去创建Go代码的目录层级,如果目录已存在则不用创建。
plugins参数有不带grpc和带grpc两种(应该还有其它的,目前知道的有这两种),两者的区别如下,带grpc的会多一些跟gRPC相关的代码,实现gRPC通信.
导入其它proto文件
有时候我们可能有多份proto文件,且每份proto文件不一定是完全独立,它们之间会互相引用,这时候该怎么做呢?
└── proto2 ├── common.proto └── greeter └── greeter.proto
greeter.proto内容如下:
syntax = "proto3"; package greeter; import "proto2/common.proto"; option go_package="proto2/greeter"; service Greeter { rpc SayHello (common.Request) returns (common.Response) {} }
以上述内容为例,假设我们有一个共用的 proto 文件 common.proto,此时 greeter.proto 如果想引用里面的message,就可以使用 import 关键字进行导入。
编译指令如下:
protoc –proto_path=. –go_out=. proto2/greeter/greeter.proto proto2/common.proto
关于protoc-gen-go的多包问题
假设目前的proto文件存放如下:
└── proto ├── common.proto ├── greeter │ └── greeter.proto └── user └── user.proto
如果你想编译所有proto文件(假设生成Go语言),正常的命令应该是这样的:
protoc --proto_path=. --go_out=. proto/*.proto proto/user/*proto proto/greeter/*proto
在服务端,我们需要在 gRPC 的基础上实现我们的服务。以下是一个简单的示例:
package main import ( "context" "net" "google.golang.org/grpc" "example.pb" // 引入刚刚生成的 ) type server struct{} func (s *server) SayHello(ctx context.Context, in *example.Message) (*example.Message, error) { return &example.Message{Data: "Hello " + in.GetData()}, nil } func main() { lis, err := net.Listen("tcp", ":50051") if err != nil { panic(err) } s := grpc.NewServer() example.RegisterGreeterServer(s, &server{}) if err := s.Serve(lis); err != nil { panic(err) } }
在该示例中,我们定义了一个名为 server 的结构体,该结构体实现了 example.GreeterServer 接口中的 SayHello 方法,该方法会接收一个名为 Message 的请求,并返回一个 Message 类型的响应。
实现客户端
在客户端,我们需要调用服务端的服务,并处理服务端的响应。以下是一个简单的示例:
package main import ( "context" "log" "google.golang.org/grpc" "example.pb" // 引入刚刚生成的 ) func main() { conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure()) if err != nil { panic(err) } defer conn.Close() c := example.NewGreeterClient(conn) response, err := c.SayHello(context.Background(), &example.Message{Data: "World"}) if err != nil { panic(err) } log.Printf("Response: %s", response.GetData()) }
在该示例中,我们使用 grpc.Dial 方法连接服务端,创建了一个名为 GreeterClient 的客户端,然后调用了 SayHello 方法。
启动服务端和客户端
现在,我们已经完成整个项目的代码编写,可以开始启动服务端和客户端了。首先,我们需要在终端中启动服务端:
go run server.go
接下来,在另一个终端中启动客户端:
go run client.go
如果一切顺利,你应该可以在客户端终端中看到以下信息:
Response: Hello World
结论
Go gRPC 是一个快速、轻量、高效、易于使用的RPC框架,能够提供出色的性能和灵活性,在 Go Web 开发中应用广泛。本文介绍了 Go gRPC 的安装、开发和使用方法,并通过一个简单的示例来展示了如何在 Go 中使用 gRPC。