跟着gRPC源码简单学习RPC原理

栏目: IT技术 · 发布时间: 4年前

内容简介:RPC(Remote Procedure Call/远程过程调用)是一种服务间交互的方式,达到看看源码,简单了解gRPC是怎么实现RPC的,以gRPC官方代码示例先看一下服务端怎么注册服务。

RPC(Remote Procedure Call/远程过程调用)是一种服务间交互的方式,达到 像本地方法一样调用远程方法 的目的。

看看源码,简单了解gRPC是怎么实现RPC的,以gRPC官方代码示例 helloworld 为例。

服务注册

先看一下服务端怎么注册服务。

helloworld.pb.go 文件中,会有 RegisterGreeterServer 方法以及 _Greeter_serviceDesc 变量,

_Greeter_serviceDesc 描述了服务的属性。 RegisterGreeterServer 方法会向gRPC服务端 s 注册服务 srv

//...
func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
    s.RegisterService(&_Greeter_serviceDesc, srv)
}
//...
var _Greeter_serviceDesc = grpc.ServiceDesc{
    ServiceName: "helloworld.Greeter", // ServiceName包括`.proto`文件中的package名称
    HandlerType: (*GreeterServer)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "SayHello",
            Handler:    _Greeter_SayHello_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "helloworld.proto",
}

server.go 中的 RegisterService 方法,会判断ServiceServer是否实现sd中描述的HandlerType;如果实现了则调用 s.register 方法注册。

func (s *Server) RegisterService(sd *ServiceDesc, ss interface{}) {
    ht := reflect.TypeOf(sd.HandlerType).Elem()
    st := reflect.TypeOf(ss)
    if !st.Implements(ht) { // 判断ServiceServer是否实现sd中描述的HandlerType
        grpclog.Fatalf("grpc: Server.RegisterService found the handler of type %v that does not satisfy %v", st, ht)
    }
    s.register(sd, ss)
}

register 根据 Method 创建对应的map,并将名称作为键,方法描述(指针)作为值,添加到相应的map中。

最后将{服务名称:服务}添加到服务端。

func (s *Server) register(sd *ServiceDesc, ss interface{}) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.printf("RegisterService(%q)", sd.ServiceName)
    if s.serve {// 服务端是否启动
        grpclog.Fatalf("grpc: Server.RegisterService after Server.Serve for %q", sd.ServiceName)
    }
    if _, ok := s.m[sd.ServiceName]; ok {//服务是否已经注册
        grpclog.Fatalf("grpc: Server.RegisterService found duplicate service registration for %q", sd.ServiceName)
    }
    srv := &service{
        server: ss,
        md:     make(map[string]*MethodDesc), // map of Methods
        sd:     make(map[string]*StreamDesc), // map of Stream
        mdata:  sd.Metadata,
    }
    for i := range sd.Methods {
        d := &sd.Methods[i]
        srv.md[d.MethodName] = d
    }
    for i := range sd.Streams {
        d := &sd.Streams[i]
        srv.sd[d.StreamName] = d
    }
    s.m[sd.ServiceName] = srv // 添加服务到服务端
}

服务调用

服务端注册了服务之后,接下来就是调用服务。

客户端调用服务

helloworld.pb.go 中的 SayHello 方法中使用 c.cc.Invoke 远程调用服务端:

func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
    out := new(HelloReply)
    // 远程调用服务端的方法
    err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

Invoke 的定义如下, "/helloworld.Greeter/SayHello" 对应的是 method 参数。

func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error

method 被传入后,依次被 invokenewClientStream 方法调用,保存在 cs.callHdr.Method ;后续在 newAttemptLocked 方法中生成 cs.attempt.t

cs.SendMsg 最终通过 csAttempt.sendMsg 方法中调用 a.t.Write 方法写出请求 req

最后 cs.RecvMsg 轮询获取返回结果。

func invoke(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error {
    cs, err := newClientStream(ctx, unaryStreamDesc, cc, method, opts...)
    if err != nil {
        return err
    }
    if err := cs.SendMsg(req); err != nil {
        return err
    }
    return cs.RecvMsg(reply)
}

服务端执行调用

handleStream 方法会处理请求中的 Method 字段,获得服务名与方法名。调用 s.processUnaryRPC , 调用 md.Handler 方法(即 _Greeter_SayHello_Handler 方法)。

最终调用 s.sendResponse 方法返回结果。

func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(HelloRequest)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(GreeterServer).SayHello(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/helloworld.Greeter/SayHello",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
    }
    return interceptor(ctx, in, info, handler)
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

云计算安全与隐私

云计算安全与隐私

Tim Mather、Subra Kumaraswamy、Shahed Latif / 刘戈舟、杨泽明、刘宝旭 / 机械工业出版社华章公司 / 2011-6 / 65.00元

《云计算安全与隐私》可以使你明白当把数据交付给云计算时你所面临的风险,以及为了保障虚拟基础设施和网络应用程序的安全可以采取的行动。本书是由信息安全界知名专家所著,作者在书中给出许多中肯的忠告和建议。本书的读者对象包括:IT职员、信息安全和隐私方面的从业人士、业务经理、服务提供商,以及投资机构等。阅读本书你会了解直到现在还严重匮乏的云计算安全方面的详尽信息。 《云计算安全与隐私》主要内容包括:......一起来看看 《云计算安全与隐私》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具