原文在这里。
本教程为Go程序员提供了使用gRPC的基本介绍。
通过跟随本示例,你将学会如何:
- 在.proto文件中定义一个服务。
- 使用协议缓冲编译器生成服务器和客户端代码。
- 使用Go gRPC API编写一个简单的服务端和客户端。
本教程假设你已经阅读了gRPC入门并熟悉协议缓冲(Protocol Buffers)。请注意,本教程中的示例使用了proto3版本的协议缓冲语言。你可以在proto3语言指南和Go生成的代码指南中了解更多信息。
为什么使用gRPC?
本示例是一个简单的路线映射应用程序,允许客户端获取有关其路线上的特点信息,创建其路线的摘要,并与服务器和其他客户端交换路线信息,如交通更新。
通过gRPC,我们可以在.proto文件中定义我们的服务,并在gRPC支持的任何语言中生成客户端和服务器。这些代码可以运行在从大型数据中心内的服务器到你自己的平板电脑等各种环境中,gRPC会为你处理不同语言和环境之间的通信复杂性。我们还可以获得与协议缓冲一起工作的所有优势,包括高效的序列化、简单的IDL和易于更新的接口。
设置
在开始之前,你应该已经安装了生成客户端和服务器接口代码所需的工具。如果还没有安装,请参考快速入门指南的先决条件部分进行安装设置。
获取示例代码
示例代码位于grpc-go仓库中。
你可以下载该仓库的zip文件并解压,或者通过克隆仓库来获取示例代码:
$ git clone -b v1.56.2 --depth 1 https://github.com/grpc/grpc-go
然后进入示例代码的目录:
$ cd grpc-go/examples/route_guide
定义服务
作为第一步,我们需要使用protocol buffers来定义gRPC服务以及方法请求和响应类型。完整的.proto
文件可以在routeguide/route_guide.proto中找到。
在.proto文件中,要定义一个服务,你需要在其中指定一个命名的服务:
service RouteGuide {
...
}
然后在服务定义内部定义rpc
方法,并指定它们的请求和响应类型。gRPC允许你定义四种类型的服务方法,其中在RouteGuide服务中都会使用到:
- 一个简单的RPC,客户端使用存根(stub)向服务器发送请求,并等待响应返回,就像普通的函数调用一样。
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
- 一个服务端流式RPC,在这种RPC中,客户端发送请求给服务器,并获得一个流以读取一系列的响应消息。客户端从返回的流中读取,直到没有更多的消息为止。在我们的例子中,你可以通过在响应类型之前使用stream关键字来指定一个服务端流式方法。
// Obtains the Features available within the given Rectangle. Results are
// streamed rather than returned at once (e.g. in a response message with a
// repeated field), as the rectangle may cover a large area and contain a
// huge number of features.
rpc ListFeatures(Rectangle) returns (stream Feature) {}
- 客户端流式RPC,客户端编写一系列消息并通过提供的流发送到服务器。一旦客户端完成写入消息,它会等待服务器读取所有消息并返回响应。你可以通过在请求类型之前放置
stream
关键字来指定客户端流式方法。
// Accepts a stream of Points on a route being traversed, returning a
// RouteSummary when traversal is completed.
rpc RecordRoute(stream Point) returns (RouteSummary) {}
- 双向流式RPC,双方使用读写流发送一系列消息。两个流操作独立,因此客户端和服务器可以按任意顺序读取和写入:例如,服务器可以在写入其响应之前等待接收所有客户端消息,或者可以交替读取消息然后写入消息,或者进行一些其他读取和写入的组合。每个流中消息的顺序保持不变。你可以通过在请求类型和响应类型之前都放置stream关键字来指定这种类型的方法。
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
我们的.proto
文件还包含了用于所有服务方法中的请求和响应类型的协议缓冲区消息类型定义 - 例如,这里是Point消息类型的定义:
// Points are represented as latitude-longitude pairs in the E7 representation
// (degrees multiplied by 10**7 and rounded to the nearest integer).
// Latitudes should be in the range +/- 90 degrees and longitude should be in
// the range +/- 180 degrees (inclusive).
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
在上面的代码中,我们定义了一个名为Point的消息类型,它包含两个字段:latitude和longitude,分别对应整数类型的字段标识为1和2。这个消息类型可以用来表示地理位置的纬度和经度信息。
生成客户端和服务器代码
接下来,我们需要从.proto
服务定义生成gRPC客户端和服务器接口。我们使用protoc
以及gRPC Go插件来完成这个任务。
在examples/route_guide
目录中,运行以下命令:
$ protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
routeguide/route_guide.proto
运行这个命令会在routeguide目录下生成以下文件:
route_guide.pb.go
:包含所有协议缓冲区代码,用于填充、序列化和检索请求和响应消息类型。route_guide_grpc.pb.go
:包含以下内容:- 一个接口类型(或存根),供客户端调用,其中定义了
RouteGuide
服务中的方法。 - 一个接口类型,供服务器实现,也包含
RouteGuide
服务中定义的方法。
- 一个接口类型(或存根),供客户端调用,其中定义了
创建服务
首先,让我们看一下如何创建一个RouteGuide服务器。如果你只关心创建gRPC客户端,可以跳过本节,直接查看创建客户端部分(不过你可能还是会