gRPC

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

查看生成的pg.go文件

客户端

可以看到主要生成了以下几个内容

  1. 一个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)
    
    }

  2. 一个名为wdyRouteClient的实现,实现了方法GetFeature.

    
    type wdyRouteClient struct {
    
       cc *grpc.ClientConn
    
    }
    
    func (c wdyRouteClient) GetFeature(ctx context.Context, in *Point, opts ...grpc.CallOption) (Feature, 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
    
    }

  3. 一个函数NewWdyRouteClient用来创建WdyRouteClient,如下:

func NewWdyRouteClient(cc *grpc.ClientConn) WdyRouteClient {

    return &wdyRouteClient{cc}

}

server api

主要生成以下内容:

  1. 生成了名为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)
    
    }

  2. 名为 _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, in, info, handler)
    }

  3. 还有注册server的函数如下:

func RegisterWdyRouteServer(s *grpc.Server, srv WdyRouteServer) {

    s.RegisterService(&_WdyRoute_serviceDesc, srv)

}

SERVER-to-client streaming RPC

定义接口

在proto文件中service WdyRoute中增加

 rpc ListFeatures(Rectangle) returns (stream Feature) {}

执行编译

protoc -I wdyroute/ wdyroute/wdy_route.proto --go_out=plugins=grpc:wdyroute

查看生成的pb.go文件

客户端

pb.go文件中相比之前还增加了

  1. 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数据。

  1. WdyRouteClient interface 的实例wdyRouteClient 也实现了方法 ListFeatures 如下:
func (c *wdyRouteClient) ListFeatures(ctx context.Context, in *Rectangle, opts ...grpc.CallOption) (WdyRoute_ListFeaturesClient, error) {

    stream, err := grpc.NewClientStream(ctx, &_WdyRoute_serviceDesc.Streams[0], c.cc, "/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

}
  1. .新的接口 WdyRoute_ListFeaturesClient,该接口定义了方法Recv 用于client接受数据;
type WdyRoute_ListFeaturesClient interface {

    Recv() (*Feature, error)

    grpc.ClientStream

}
  1. WdyRoute_ListFeaturesClient interface的实例 wdyRouteListFeaturesClient的定义;
type wdyRouteListFeaturesClient struct {

    grpc.ClientStream

}
  1. 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

server端代码相比之前增加

  1. WdyRouteServer interface中相比之前增加了方法 ListFeatures, 方法ListFeatures的第二个参数为WdyRoute_ListFeaturesServer interface;
type WdyRouteServer interface {

    ...

    ListFeatures(*Rectangle, WdyRoute_ListFeaturesServer) error

    ...

}

WdyRoute_ListFeaturesServer用于server发送stream数据

  1. _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})

}
  1. WdyRoute_ListFeaturesServer interface,定义了方法 Send 用于server发送stream数据
type WdyRoute_ListFeaturesServer interface {

    Send(*Feature) error

    grpc.ServerStream

}
  1. 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.

定义接口

在proto文件service WdyRoute中增加

  rpc RecordRoute(stream Point) returns (RouteSummary) {}

执行编译

protoc -I wdyroute/ wdyroute/wdy_route.proto --go_out=plugins=grpc:wdyroute

查看生成的pb.go文件

客户端

  1. type WdyRouteClient interface增加方法 RecordRoute
    // 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数据。

  1. wdyRouteClient 新实现了方法 RecordRoute,该方法返回WdyRoute_RecordRouteClient interface
func (c *wdyRouteClient) RecordRoute(ctx context.Context, opts ...grpc.CallOption) (WdyRoute_RecordRouteClient, error) {

    stream, err := grpc.NewClientStream(ctx, &_WdyRoute_serviceDesc.Streams[1], c.cc, "/wdyroute.WdyRoute/RecordRoute", opts...)

    if err != nil {

        return nil, err

    }

    x := &wdyRouteRecordRouteClient{stream}

    return x, nil

}
  1. WdyRoute_RecordRouteClient interface的定义,该接口含有方法Send和CloseAndRecv,用于发送stream数据。
type WdyRoute_RecordRouteClient interface {

    Send(*Point) error

    CloseAndRecv() (*RouteSummary, error)

    grpc.ClientStream

}
  1. 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, err

    }

    return m, nil

}

server api

server端代码相比之前增加

  1. 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接收数据.

  1. _WdyRoute_RecordRoute_Handler
func _WdyRoute_RecordRoute_Handler(srv interface{}, stream grpc.ServerStream) error {

    return srv.(WdyRouteServer).RecordRoute(&wdyRouteRecordRouteServer{stream})

}
  1. WdyRoute_RecordRouteServer interface ,定义接口SendAndClose和Recv,用于server接收数据.
type WdyRoute_RecordRouteServer interface {

    SendAndClose(*RouteSummary) error

    Recv() (*Point, error)

    grpc.ServerStream

}
  1. 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, err

    }

    return m, nil

}

A Bidirectional streaming RPC.

定义接口

在proto文件中service WdyRoute中增加

//

  // 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文件

客户端

  1. type WdyRouteClient interface增加方法 RecordRoute
    // 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数据。

  1. wdyRouteClient对方法RouteChat的实现
func (c *wdyRouteClient) RouteChat(ctx context.Context, opts ...grpc.CallOption) (WdyRoute_RouteChatClient, error) {

    stream, err := grpc.NewClientStream(ctx, &_WdyRoute_serviceDesc.Streams[2], c.cc, "/wdyroute.WdyRoute/RouteChat", opts...)

    if err != nil {

        return nil, err

    }

    x := &wdyRouteRouteChatClient{stream}

    return x, nil

}
  1. WdyRoute_RouteChatClient interface 的定义
type WdyRoute_RouteChatClient interface {

    Send(*RouteNote) error

    Recv() (*RouteNote, error)

    grpc.ClientStream

}
  1. 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, err

    }

    return m, nil

}

server api

server端代码相比之前增加

  1. WdyRouteServer interface中相比之前增加了方法 RouteChat, 方法 RouteChat 的参数为 WdyRoute_RouteChatServer interface;
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接收和发送数据.

  1. _WdyRoute_RouteChat_Handler
func _WdyRoute_RouteChat_Handler(srv interface{}, stream grpc.ServerStream) error {

    return srv.(WdyRouteServer).RouteChat(&wdyRouteRouteChatServer{stream})

}
  1. WdyRoute_RouteChatServer interface 的定义,该接口定义了方法Send,Recv用于从stream发送和接受数据
type WdyRoute_RouteChatServer interface {

    Send(*RouteNote) error

    Recv() (*RouteNote, error)

    grpc.ServerStream

}
  1. 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, err

    }

    return m, nil

}

遇到问题

这里写图片描述

原因是命令写错了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值