Fork me on GitHub

版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc

1. 前言

读者们可能使用过 fullstorydev/grpcurl 来对grpc服务进行调用调试。

假定有一个简单的grpc的服务
main.go

package main

import (
    "context"
    "log"
    "net"

    "google.golang.org/grpc"
    pb "google.golang.org/grpc/examples/helloworld/helloworld"
    "google.golang.org/grpc/reflection"
)

const (
    port = ":50051"
)

// server is used to implement helloworld.GreeterServer.
type server struct {
    pb.UnimplementedGreeterServer
}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    log.Printf("Received: %v", in.GetName())
    return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()

    helloService := &server{}
    pb.RegisterGreeterServer(s, helloService)
    // 注册反射服务
    // Register reflection service on gRPC server.
    reflection.Register(s)

    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}    

使用grpcurl来请求grpc服务

grpcurl --plaintext -d '{"name":"vearne"}' 127.0.0.1:50051 helloworld.Greeter/SayHello|jq

output:

{
  "message": "Hello vearne"
}

jq 命令用于解析JSON字符串

读者可能会好奇,grpc服务GreeterServer明明使用的protobuf进行编码。而我们却能用JSON格式与它进行交互?

2. 解决疑惑

事实是,grpc协议提供了反射机制使得grpcurl可以知道GreeterServer的service定义,包含方法定义、请求参数、返回响应等等

2.1 输出方法定义

grpcurl --plaintext 127.0.0.1:50051 describe helloworld.Greeter.SayHello

output:

helloworld.Greeter.SayHello is a method:
rpc SayHello ( .helloworld.HelloRequest ) returns ( .helloworld.HelloReply );

2.2 获得方法的Request定义

grpcurl --plaintext 127.0.0.1:50051 describe .helloworld.HelloRequest

output:

helloworld.HelloRequest is a message:
message HelloRequest {
  string name = 1;
}

2.3 获得方法的Response定义

grpcurl --plaintext 127.0.0.1:50051 describe .helloworld.HelloReply

output:

helloworld.HelloReply is a message:
message HelloReply {
  string message = 1;
}

如果读者有心的话,可能会发现

grpcurl --plaintext 127.0.0.1:50051 list

output:

grpc.reflection.v1alpha.ServerReflection    // 反射服务
helloworld.Greeter                          // 正常的业务服务

没错,其实在监听在50051端口的有2个grpc服务。
进一步

grpcurl --plaintext 127.0.0.1:50051 describe grpc.reflection.v1alpha.ServerReflection

output:

grpc.reflection.v1alpha.ServerReflection is a service:
service ServerReflection {
  rpc ServerReflectionInfo ( stream .grpc.reflection.v1alpha.ServerReflectionRequest ) returns ( stream .grpc.reflection.v1alpha.ServerReflectionResponse );
}

ServerReflection服务可以供client查询其它grpc服务的定义。
这个服务的proto定义在参考资料2中,可以留意到它是双向流。具体可以参见参考资料2

参考资料

  1. GRPC Server Reflection Protocol
  2. reflection.proto

微信公众号

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注