gRPC入门
刚学习gRPC的时候,对stream中client和server的操作一直很困惑,为什么除了普通的Send和Recv还有额外的函数,而这些函数之间怎么区分?
后来通过自己编写proto文件,逐个server的相关接口,才明白这些接口是protoc在生成pb.go时同时生成的,对于不同的stream方式生成的函数也不同
SIMPLE RPC
首先我们定义最简单的接口GetFeature如下,结构类型的定义就不列出了,大家可以参看https://grpc.io/docs/tutorials/basic/go.html中的定义
service WdyRoute {
// A simple RPC.
rpc GetFeature(Point) returns (Feature) {}
}
执行编译
protoc -I wdyroute/ wdyroute/wdy_route.proto --go_out=plugins=grpc:wdyroute
客户端
一个WdyRouteClient的interface,接口定义方法GetFeature.
// Client API for WdyRoute service type WdyRouteClient interface { // A simple RPC. // // Obtains the feature at a given position. // // A feature with an empty name is returned if there's no feature at the given // position. GetFeature(ctx context.Context,in Point,opts ...grpc.CallOption) (Feature,error) }
一个名为wdyRouteClient的实现,实现了方法GetFeature.
type wdyRouteClient struct { cc *grpc.ClientConn } func (c wdyRouteClient) GetFeature(ctx context.Context,in *Point,error) { out := new(Feature) err := grpc.Invoke(ctx,"/wdyroute.WdyRoute/GetFeature",in,out,c.cc,opts...) if err != nil { return nil,err } return out,nil }
一个函数NewWdyRouteClient用来创建WdyRouteClient,如下:
func NewWdyRouteClient(cc *grpc.ClientConn) WdyRouteClient {
return &wdyRouteClient{cc}
}
server api
生成了名为WdyRouteServer的interface,方法为GetFeature;
type WdyRouteServer interface { // A simple RPC. // // Obtains the feature at a given position. // // A feature with an empty name is returned if there's no feature at the given // position. GetFeature(context.Context,Point) (Feature,error) }
名为 _WdyRoute_GetFeature_Handler 的handler 用来处理客户端的GetFeature的RPC请求.
func _WdyRoute_GetFeature_Handler(srv interface{},ctx context.Context,dec func(interface{}) error,interceptor grpc.UnaryServerInterceptor) (interface{},error) { in := new(Point) if err := dec(in); err != nil { return nil,err } if interceptor == nil { return srv.(WdyRouteServer).GetFeature(ctx,in) } info := &grpc.UnaryServerInfo{ Server: srv,FullMethod: "/wdyroute.WdyRoute/GetFeature",} handler := func(ctx context.Context,req interface{}) (interface{},error) { return srv.(WdyRouteServer).GetFeature(ctx,req.(*Point)) } return interceptor(ctx,info,handler) }
func RegisterWdyRouteServer(s *grpc.Server,srv WdyRouteServer) {
s.RegisterService(&_WdyRoute_serviceDesc,srv)
}
SERVER-to-client streaming RPC
定义接口
rpc ListFeatures(Rectangle) returns (stream Feature) {}
执行编译
protoc -I wdyroute/ wdyroute/wdy_route.proto --go_out=plugins=grpc:wdyroute
客户端
- type WdyRouteClient interface 中相比之前增加了方法 ListFeatures,该方法返回一个WdyRoute_ListFeaturesClient的interface,如下:
// A server-to-client streaming RPC.
//
// 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.
ListFeatures(ctx context.Context,in *Rectangle,opts ...grpc.CallOption) (WdyRoute_ListFeaturesClient,error)
WdyRoute_ListFeaturesClient 用于client读取stream数据。
- WdyRouteClient interface 的实例wdyRouteClient 也实现了方法 ListFeatures 如下:
func (c *wdyRouteClient) ListFeatures(ctx context.Context,error) {
stream,err := grpc.NewClientStream(ctx,&_WdyRoute_serviceDesc.Streams[0],"/wdyroute.WdyRoute/ListFeatures",opts...)
if err != nil {
return nil,err
}
x := &wdyRouteListFeaturesClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil,err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil,err
}
return x,nil
}
- .新的接口 WdyRoute_ListFeaturesClient,该接口定义了方法Recv 用于client接受数据;
type WdyRoute_ListFeaturesClient interface {
Recv() (*Feature,error)
grpc.ClientStream
}
- WdyRoute_ListFeaturesClient interface的实例 wdyRouteListFeaturesClient的定义;
type wdyRouteListFeaturesClient struct {
grpc.ClientStream
}
- wdyRouteListFeaturesClient 实现方法Recv用于客户端从server读取stream数据;
func (x wdyRouteListFeaturesClient) Recv() (Feature,error) {
m := new(Feature)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil,err
}
return m,nil
}
server api
- WdyRouteServer interface中相比之前增加了方法 ListFeatures,方法ListFeatures的第二个参数为WdyRoute_ListFeaturesServer interface;
type WdyRouteServer interface {
...
ListFeatures(*Rectangle,WdyRoute_ListFeaturesServer) error
...
}
WdyRoute_ListFeaturesServer用于server发送stream数据
- _WdyRoute_ListFeatures_Handler
func _WdyRoute_ListFeatures_Handler(srv interface{},stream grpc.ServerStream) error {
m := new(Rectangle)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(WdyRouteServer).ListFeatures(m,&wdyRouteListFeaturesServer{stream})
}
- WdyRoute_ListFeaturesServer interface,定义了方法 Send 用于server发送stream数据
type WdyRoute_ListFeaturesServer interface {
Send(*Feature) error
grpc.ServerStream
}
- WdyRoute_ListFeaturesServer interface的实例 wdyRouteListFeaturesServer 以及方法Send的实现
type wdyRouteListFeaturesServer struct {
grpc.ServerStream
}
func (x *wdyRouteListFeaturesServer) Send(m *Feature) error {
return x.ServerStream.SendMsg(m)
}
A CLIENT-to-server streaming RPC.
定义接口
rpc RecordRoute(stream Point) returns (RouteSummary) {}
执行编译
protoc -I wdyroute/ wdyroute/wdy_route.proto --go_out=plugins=grpc:wdyroute
客户端
// A client-to-server streaming RPC.
//
// Accepts a stream of Points on a route being traversed,returning a
// RouteSummary when traversal is completed.
RecordRoute(ctx context.Context,opts ...grpc.CallOption) (WdyRoute_RecordRouteClient,error)
WdyRoute_RecordRouteClient用于client发送stream数据。
func (c *wdyRouteClient) RecordRoute(ctx context.Context,&_WdyRoute_serviceDesc.Streams[1],"/wdyroute.WdyRoute/RecordRoute",err
}
x := &wdyRouteRecordRouteClient{stream}
return x,nil
}
- WdyRoute_RecordRouteClient interface的定义,该接口含有方法Send和CloseAndRecv,用于发送stream数据。
type WdyRoute_RecordRouteClient interface {
Send(*Point) error
CloseAndRecv() (*RouteSummary,error)
grpc.ClientStream
}
- WdyRoute_RecordRouteClient interface的实例wdyRouteRecordRouteClient以及对方法Send和CloseAndRecv的定义
type wdyRouteRecordRouteClient struct {
grpc.ClientStream
}
func (x *wdyRouteRecordRouteClient) Send(m *Point) error {
return x.ClientStream.SendMsg(m)
}
func (x wdyRouteRecordRouteClient) CloseAndRecv() (RouteSummary,error) {
if err := x.ClientStream.CloseSend(); err != nil {
return nil,err
}
m := new(RouteSummary)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil,nil
}
server api
- WdyRouteServer interface中相比之前增加了方法 RecordRoute,方法 RecordRoute 的参数为 WdyRoute_RecordRouteServer interface;
type WdyRouteServer interface {
...
// A client-to-server streaming RPC.
//
// Accepts a stream of Points on a route being traversed,returning a
// RouteSummary when traversal is completed.
RecordRoute(WdyRoute_RecordRouteServer) error
...
}
WdyRoute_RecordRouteServer 用于server接收数据.
- _WdyRoute_RecordRoute_Handler
func _WdyRoute_RecordRoute_Handler(srv interface{},stream grpc.ServerStream) error {
return srv.(WdyRouteServer).RecordRoute(&wdyRouteRecordRouteServer{stream})
}
- WdyRoute_RecordRouteServer interface,定义接口SendAndClose和Recv,用于server接收数据.
type WdyRoute_RecordRouteServer interface {
SendAndClose(*RouteSummary) error
Recv() (*Point,error)
grpc.ServerStream
}
- WdyRoute_RecordRouteServer interface的实例wdyRouteRecordRouteServer以及对方法SendAndClose和Recv的实现
type wdyRouteRecordRouteServer struct {
grpc.ServerStream
}
func (x *wdyRouteRecordRouteServer) SendAndClose(m *RouteSummary) error {
return x.ServerStream.SendMsg(m)
}
func (x wdyRouteRecordRouteServer) Recv() (Point,error) {
m := new(Point)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil,nil
}
A Bidirectional streaming RPC.
定义接口
//
// 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) {}
执行编译
protoc -I wdyroute/ wdyroute/wdy_route.proto --go_out=plugins=grpc:wdyroute
查看生产的pb.go文件
客户端
// A Bidirectional streaming RPC.
//
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
RouteChat(ctx context.Context,opts ...grpc.CallOption) (WdyRoute_RouteChatClient,error)
WdyRoute_RouteChatClient 用于client发送stream数据。
- wdyRouteClient对方法RouteChat的实现
func (c *wdyRouteClient) RouteChat(ctx context.Context,&_WdyRoute_serviceDesc.Streams[2],"/wdyroute.WdyRoute/RouteChat",err
}
x := &wdyRouteRouteChatClient{stream}
return x,nil
}
- WdyRoute_RouteChatClient interface 的定义
type WdyRoute_RouteChatClient interface {
Send(*RouteNote) error
Recv() (*RouteNote,error)
grpc.ClientStream
}
- WdyRoute_RouteChatClient interface 的实例wdyRouteRouteChatClient的定义以及对方法Send和Recv的实现
type wdyRouteRouteChatClient struct {
grpc.ClientStream
}
func (x *wdyRouteRouteChatClient) Send(m *RouteNote) error {
return x.ClientStream.SendMsg(m)
}
func (x wdyRouteRouteChatClient) Recv() (RouteNote,error) {
m := new(RouteNote)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil,nil
}
server api
type WdyRouteServer interface {
...
// A Bidirectional streaming RPC.
//
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
RouteChat(WdyRoute_RouteChatServer) error
...
}
WdyRoute_RouteChatServer 用于server接收和发送数据.
- _WdyRoute_RouteChat_Handler
func _WdyRoute_RouteChat_Handler(srv interface{},stream grpc.ServerStream) error {
return srv.(WdyRouteServer).RouteChat(&wdyRouteRouteChatServer{stream})
}
- WdyRoute_RouteChatServer interface 的定义,该接口定义了方法Send,Recv用于从stream发送和接受数据
type WdyRoute_RouteChatServer interface {
Send(*RouteNote) error
Recv() (*RouteNote,error)
grpc.ServerStream
}
- WdyRoute_RouteChatServer interface 的实例wdyRouteRouteChatServer
type wdyRouteRouteChatServer struct {
grpc.ServerStream
}
func (x *wdyRouteRouteChatServer) Send(m *RouteNote) error {
return x.ServerStream.SendMsg(m)
}
func (x wdyRouteRouteChatServer) Recv() (RouteNote,error) {
m := new(RouteNote)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil,nil
}
遇到问题
原因是命令写错了。
原文链接:https://www.f2er.com/go/187493.html