本页描述了用protoc编译.proto文件时,用grpc插件protoc-gen-go-grpc生成的代码。
你可以在服务定义中了解如何在.proto文件中定义一个gRPC服务。
线程安全:请注意,客户端的RPC调用和服务器端的RPC处理程序是线程安全的,是为了在并发的goroutine上运行。但也要注意,对于单个流来说,传入和传出的数据是双向的,但却是串行的;因此,例如单个流不支持并发的读或并发的写(但读和写是安全地并发的)。
生成的服务器接口上的方法
在服务器端,.proto文件中的每个服务Bar都会产生函数。
func RegisterBarServer(s *grpc.Server, srv BarServer)
应用程序可以定义一个BarServer接口的具体实现,并通过使用这个函数将其注册到grpc.Server实例中(在启动服务器实例之前)。
单项方法
这些方法在生成的服务接口上有如下签名。
Foo(context.Context, *MsgA) (*MsgB, error)
在这个上下文中,MsgA是客户端发送的protobuf消息,MsgB是服务器发回的protobuf消息。
服务器流的方法
这些方法在生成的服务接口上有如下签名。
Foo(*MsgA, <ServiceName>_FooServer) error
在这种情况下,MsgA是来自客户端的单一请求,<ServiceName>_FooServer参数代表服务器到客户端的MsgB消息流。
<ServiceName>_FooServer有一个嵌入式的grpc.ServerStream和以下接口。
type <ServiceName>_FooServer interface { Send(*MsgB) error grpc.ServerStream }
服务器端处理程序可以通过这个参数的发送方法向客户端发送一个protobuf消息流。服务器到客户端的流的结束是由处理程序方法的返回引起的。
客户端流的方法
这些方法在生成的服务接口上有如下签名。
Foo(<ServiceName>_FooServer) 错误
在这种情况下,<ServiceName>_FooServer既可以用来读取客户端到服务器的消息流,也可以用来发送单个服务器响应消息。
<ServiceName>_FooServer有一个嵌入式的grpc.ServerStream和以下接口。
type <ServiceName>_FooServer interface { SendAndClose(*MsgA) error Recv() (*MsgB, error) grpc.ServerStream }
服务器端处理程序可以重复调用这个参数的Recv,以便从客户端接收完整的消息流。一旦Recv到达流的末端,它将返回(nil, io.EOF)。来自服务器的单一响应消息是通过调用该<ServiceName>_FooServer参数的SendAndClose方法发送的。请注意,SendAndClose必须被调用一次,而且只有一次。
双向流方法
这些方法在生成的服务接口上有如下签名。
Foo(<ServiceName>_FooServer) error
在这种情况下,<ServiceName>_FooServer可以用来访问客户端到服务器的消息流和服务器到客户端的消息流。<ServiceName>_FooServer有一个嵌入式的grpc.ServerStream和以下接口。
type <ServiceName>_FooServer interface { Send(*MsgA) error Recv() (*MsgB, error) grpc.ServerStream }
服务器端处理程序可以重复调用这个参数的Recv,以读取客户端到服务器的消息流。一旦Recv到达客户端到服务器的信息流的末端,它将返回(nil, io.EOF)。通过反复调用该ServiceName>_FooServer参数上的Send方法来发送响应的服务器到客户端的消息流。服务器到客户端流的结束是通过bidi方法处理程序的返回来表示的。
生成的客户端接口上的方法
对于客户端的使用,.proto文件中的每个服务Bar也会产生一个函数:func BarClient(cc *grpc.ClientConn) BarClient,它返回一个BarClient接口的具体实现(这个具体实现也存在于生成的.pb.go文件中)。
单元方法
这些方法在生成的客户端存根上有如下签名。
(ctx context.Context, in *MsgA, opts ...grpc.CallOption) (*MsgB, error)
在这种情况下,MsgA是客户端到服务器的单一请求,MsgB包含从服务器发回的响应。
服务器流方法
这些方法在生成的客户端存根上有如下签名。
Foo(ctx context.Context, in *MsgA, opts ...grpc.CallOption) (<ServiceName>_FooClient, error)
在这种情况下,<ServiceName>_FooClient表示服务器到客户的MsgB消息流。
这个流有一个嵌入式的grpc.ClientStream和以下接口。
type <ServiceName>_FooClient interface { Recv() (*MsgB, error) grpc.ClientStream }
当客户端调用存根上的Foo方法时,该流开始了。然后,客户端可以在返回的<ServiceName>_FooClient流上重复调用Recv方法,以读取服务器到客户端的响应。