生成代码(遗留的非泛型)参考

本页描述了使用 grpc 插件 protoc-gen-go-grpc 编译 .proto 文件时生成的代码。

您可以在 服务定义 中了解如何在 .proto 文件中定义 gRPC 服务。

线程安全:请注意,客户端 RPC 调用和服务器端 RPC 处理程序是线程安全的,并且旨在并发运行在多个 goroutine 中。但是还要注意,对于单个流,输入和输出数据是双向的但按顺序处理的;例如,单个流不支持并发读取或并发写入(但是读取与写入是安全并发的)。

生成的服务器接口的方法

在服务器端,.proto 文件中的每个 service 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
}

服务器端处理程序可以通过此参数的 Send 方法向客户端发送一系列 protobuf 消息。服务器到客户端流的流结束是通过处理程序方法的 return 来实现的。

客户端流方法

这些方法在生成的服务接口中具有以下签名:

Foo(<ServiceName>_FooServer) error

在这种情况下,<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 方法来发送。服务器到客户端流的结束由双向方法处理程序的返回表示。

生成的客户端接口的方法

对于客户端使用,每个 .proto 文件中的 service 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 方法,以便读取服务器到客户端的响应流。一旦服务器到客户端的流完全读取完毕,Recv 方法将返回 (nil, io.EOF)

客户端流方法

这些方法在生成的客户端存根中具有以下签名:

Foo(ctx context.Context, opts ...grpc.CallOption) (<ServiceName>_FooClient, error)

在此上下文中,<ServiceName>_FooClient 代表从客户端到服务器的 MsgA 消息流。

<ServiceName>_FooClient 包含一个嵌入式的 grpc.ClientStream 和以下接口:

type <ServiceName>_FooClient interface {
	Send(*MsgA) error
	CloseAndRecv() (*MsgB, error)
	grpc.ClientStream
}

当客户端调用存根上的 Foo 方法时,流开始。然后,客户端可以在返回的 <ServiceName>_FooClient 流上反复调用 Send 方法,以便发送客户端到服务器的消息流。必须且仅必须在该流上调用 CloseAndRecv 方法,以同时关闭客户端到服务器的流并接收服务器的单个响应消息。

双向流方法

这些方法在生成的客户端存根中具有以下签名:

Foo(ctx context.Context, opts ...grpc.CallOption) (<ServiceName>_FooClient, error)

在这种情况下,<ServiceName>_FooClient 表示客户端到服务器和服务器到客户端的消息流。

<ServiceName>_FooClient 嵌入了 grpc.ClientStream,并具有以下接口:

type <ServiceName>_FooClient interface {
	Send(*MsgA) error
	Recv() (*MsgB, error)
	grpc.ClientStream
}

当客户端调用存根上的 Foo 方法时,流开始。然后,客户端可以在返回的 <ServiceName>_FooClient 流上重复调用 Send 方法,以发送客户端到服务器的消息流。客户端还可以在此流上重复调用 Recv 方法,以接收完整的服务器到客户端的消息流。

服务器到客户端流的结束通过 Recv 方法返回 (nil, io.EOF) 来指示。客户端到服务器流的结束可以通过客户端调用流上的 CloseSend 方法来指示。

包和命名空间

当使用 --go_out=plugins=grpc: 调用 protoc 编译器时,proto 包到 Go 包的转换方式与使用 protoc-gen-go 插件而不使用 grpc 插件时相同。

例如,如果 foo.proto 声明其所属的包为 foo,那么生成的 foo.pb.go 文件也将位于 Go 包 foo 中。