Prerequisites(先决条件)
- Go
Go的三个最新主要版本之一 - Protocol buffer 编译器,protoc,version3
https://www.jianshu.com/p/5324b412f1de - protocol 编译器的 Go 插件:
https://www.jianshu.com/p/5324b412f1de
获取示例代码
- 下载实例代码
$ git clone -b v1.46.0 --depth 1 https://github.com/grpc/grpc-go
- 切换代码目录
$ cd grpc-go/examples/helloworld
运行示例
在 examples/helloworld 目录下:
- 编译和执行服务端代码
$ go run greeter_server/main.go
- 在另外一个终端中,编译和执行客户端代码,会看到客户端输出:
$ go run greeter_client/main.go Greeting: Hello world
更新 gRPC 服务
在本节中,将使用额外的 server 方法更新应用程序。gRPC服务是使用 protocol buffers 定义的。
现在,只需要知道服务器和客户端存根都有一个 SayHello()RPC方法,该方法从客户端获取一个 HelloRequest 参数,并从服务器返回一个 HelloReply,该方法的定义如下:
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
打开 helloworld/helloworld.proto,添加一个新的方法 SayHelloAgain()
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
重新生成 gRPC 代码
在可以使用新的服务方法之前,需要重新编译更新后的 .proto 文件。
在 examples/helloworld 目录下,运行下面的命令:
$ protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
helloworld/helloworld.proto
paths:用于指定生成文件的路径的结构,有两个值:
1. paths=import 相对于导入路径, 默认值
2. paths=source_relative 相对于输入文件,即proto文件的路径
重新生成的 helloworld/helloworld.pb.go 和 helloworld/helloworld_grpc.pb.go 文件中包含:
- xxx.pb.go
它包含用于填充、序列化和检索 请求和响应消息类型 的所有protocol buffer 代码。 - xxx_grpc.pb.go
客户端使用的 服务中定义的方法调用的接口类型(或存根)。
服务器要实现的接口类型。
更新并运行应用程序
虽然已经生成了客户端、服务端代码,但是任然需要示例程序中 实现和调用 新的方法。
- 更新 服务端
打开 greeter_server/main.go 添加下面的函数:func (s *server) SayHelloAgain (ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { retrn &pb.HelloReply{Message: "Hello again " + in.GetName()}, nil }
- 更新客户端
打开 greeter_client/main.go 在 main() 函数体的最下方添加下面代码:r, err = c.SayHelloAgain(ctx, &pb.HelloRequest{Name: name}) if err != nil { log.Fatalf("could not greet : %v", err) } log.Printf("Greetine : %s", r.GetMessage())
- 运行
# 运行 server go run greeter_server/main.go # 运行 client go run greeter_client/main.go Alice # client 输出 2021/05/15 23:55:08 Greeting: Hello Alice 2021/05/15 23:55:08 Greeting: Hello again Alice
总结
- gRPC基本使用流程
在 .proto 文件中定义 service、message
通过 protocol buffer 编译器生成代码
-
创建服务端
3.1 实现 servic 中定义的接口
gRPC 允许你定义四种类型的服务方法3.2 启动一个gRPC 服务,监听客户端请求
一旦你实现了所有的方法,我们需要启动一个 gRPC 服务,目的是客户端能够使用我们的服务。
如何构建并启动一个服务:
3.2.1 指定用于 监听客户端请求的端口
lis, err := net.Listen(...)3.2.2 创建一个 gRPC 服务实例
grpcServer := grpc.NewServer(...)3.2.3 在 gRPC服务器上注册我们的服务实现
pb.RegisterRouterGuideServer(...)3.2.4 在服务器上使用 端口详细信息 调用Serve() 方法,以执行阻塞等待,直到进程被终止 或 调用 Stop()
grpcServer.Serve(...)lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port)) if err != nil { log.Fatalf("failed to listen: %v", err) } var opts []grpc.ServerOption ... grpcServer := grpc.NewServer(opts...) pb.RegisterRouteGuideServer(grpcServer, newServer()) grpcServer.Serve(lis)
创建客户端
-
创建一个stub
要调用服务方法,我们首先需要创建一个gRPC通道来与服务器通信。我们通过将服务器地址和端口号传递给 grpc.Dial() 来创建它,如下所示:var opts []grpc.DialOption ... conn, err := grpc.Dial(*serverAddr, opts...) if err != nil { ... } defer conn.Close()
可以使用 DialOptions 在 grpc.Dial 中设置身份验证凭据(例如,TLS、GCE凭据或JWT凭据),当服务需要这些凭据时可以使用它们。
一旦 gRPC通道 设置好,我们就需要一个客户端存根来执行RPC。我们使用从 .proto文件 生成的 pb包 提供的 NewRouteGuideClient方法 获得它。
client := pb.NewRouteGuideClient(conn)
调用服务方法
gRPC允许定义四种类型的服务方法执行客户端、服务端应用程序