gRPC的基础使用

131 阅读4分钟

本文将介绍gRPC在golang中的基础使用方法,包含基础了gRPC使用场景,包括四种RPC方式、metadata的使用等。

本文文章所用示例代码见go-grpc-example

参考文档:PROTOCOL-HTTP2Core-Conceptgrpc-go文档Doc

导包

go get google.golang.org/grpc

四种RPC方式

Unary RPC

客户端发送一次请求,然后服务端返回一次响应,这个就是Unary RPC。

例如下面的例子,客户端每发送一个 CreateCellphoneRequest就会得到服务端的 CreateCellphoneResponse响应。

rpc CreateCellphone(CreateCellphoneRequest) returns (CreateCellphoneResponse);

Server streaming RPC

客户端发送一次请求,服务器不再以一次性的方式返回响应,而是以数据流的方式返回响应(a stream of messages),这个就是Server streaming RPC。

在proto文件内定义rpc服务的时候,在返回值类型前面加上 stream关键字,就完成了这种类型的定义。

在这种模式下,服务端涉及的方法为 Send,用来发送数据流;客户端涉及的方法为 Recv,用来接收数据流。

例如下面的例子,客户端接收流式响应,每次接收都得到一个 Cellphone类型的数据

rpc SearchCellphone(FilterCondition) returns (stream Cellphone);

Client streaming RPC

客户端发送请求的时候以数据流的方式发送请求数据(a stream of messages),服务端接收数据流,然后返回一次性的响应数据。

这种模式下,客户端涉及的方法为 Send用来发送流数据,CloseAndRecv用来接收响应数据;服务端涉及的方法为 Recv接收请求数据流,SendAndClose用来发送响应数据。

例如下面的例子,客户端发送字节流数据给服务端,服务端处理完成后,返回一个响应。

rpc UploadCellphoneCover(stream UploadCellphoneCoverRequest) returns (UploadCellphoneCoverResponse);

注意事项:

  1. 在golang中的gRPC实现中,客户端调用 Send方法发送数据的时候,并不会阻塞等待服务端调用Recv?(从测试来看好像这样)。服务端有可能随时通过返回错误来关闭流,所以客户端每次 Send或者最后 CloseAndRecv之后都要判断错误。
  2. 如果客户端在 Send过程中发生了在客户端这一侧的错误,那么直接返回对应的 error;但是如果是服务端返回了错误,那么在客户端再使用 Send的时候,就会笼统地返回 io.EOF错误,更为具体的错误需要在客户端侧调用 RecvMsg(nil)来获得。

Bidirectional streaming RPC

客户端和服务端之间双向的数据交互都是数据流,这种方式可以发送多个请求和多个响应。

例如下面的例子。

rpc BuyCellphone(stream BuyCellphoneRequest) returns (stream BuyCellphoneResponse);

注意事项:

  1. 当客户端发送完所有的请求数据之后,调用CloseSend方法关闭写端。
  2. 服务端通过Recv不断接收请求,使用Send发送响应。

gRPC的响应状态使用

gRPC中表示响应的状态和状态码要用到这两个package

google.golang.org/grpc/codes
google.golang.org/grpc/status

通过 status.Error(c codes.Code, msg string) error这个接口可以返回响应错误信息

gRPC定义了一系列内置的错误码,可以在codes中设置,常见的错误码比如 codes.OK, codes.Canceled, codes.InvalidArgument等。


context.Context在gRPC中的使用

超时控制

使用 context.WithTimeout或者 context.WithDeadline

调用取消

使用 context.WithCancel


gPRC中时间类型的使用

在proto文件中 import "google/protobuf/timestamp.proto",这个是protobuf的内置message类型,用来表示时间戳。

生成的go代码中,类型为 timestamppb.Timestamp

time.Time的相互转换:

timestamppb.Timestamp -> time.TimeAsTime方法可以转化为go的内置 time.Time类型,timestamppb.Timestamp.AsTime()

time.Time -> timestamppb.Timestamptimestamppb.New(time.Time)


gRPC中的metadata/trailer

metadata

gRPC中的metadata是可以在传输携带的一组键值对数据,键值对的类型一般都是字符串,也可以是二进制数据。

获取metadata

使用grpc中的metadata包来获取(google.golang.org/grpc/metadata),metadata依附在context.Context中。

创建带有metadata的Context

使用 metadata.NewOutgoingContext函数完成context的创建;或者使用 metadata.AppendToOutgoingContext函数。

response trailer/header

服务端响应的时候,除了主体信息外,还可以额外携带header信息和trailer信息,即gRPC完成响应后额外传输的一组数据,也是键值对的形式。

Unary RPC和Streaming RPC获取响应的trailer和header不一样。

  • Unary RPC获取响应的trailer/header:使用 grpc.Trailer(&metadata.MD)grpc.Header(&metadata.MD)生成 grpc.CallOption,作为选项传入。
  • Streaming RPC获取trailer/header:在stream上调用Trailer()或者Header()方法。