gRPC调用过程分析

gRPC代码示例

// server
type SearchService struct{}
func (s *SearchService) Search(ctx context.Context, req *pb.SearchRequest) (*pb.SearchResponse, error) {
    return &pb.SearchResponse{Response: req.GetRequest() + "Server"}, nil
}
func main() {
    grpcserver := grpc.NewServer()
    pb.RegisterSearchServiceServer(grpcserver, &SearchService{})
    lis, err := net.Listen("tcp", ":9001")
	if err != nil {
		log.Fatal("Listen Err", err)
    }
    grpcserver.Serve(lis)
}

// client
func main() {
    conn, err := grpc.Dial(":9001",grpc.WithInsecure())
    if err != nil {
		log.Fatalf("Dial Err: %v", err)
    }
    defer conn.Close()
    client := pb.NewSearchServiceClient(conn)
    resp, err := client.Search(ctx,&pb.SearchRequest{Request: "grpc Test"})
    if err != nil {
		log.Fatal("client.Search", err)
    }		
}

服务端注册并启动服务等待客户端调用

// 服务端初始化
NewServer() 初始化server 配置,采用function options的方式传入参数
RegisterSearchServiceServer   注册服务 实际为调用别的函数`search.pb.go`
  |- RegisterService  获取类型,并判断是否传入的结构体是否实现了接口  `server.go`
    |- register       将定义的方法  方法名等信息保存至初始化的server的配置中 这里将普通的方法和流式传输的方法分开存储
Listen 创建socket链接
Serve() 启动服务,等待接收调用方的请求
  |- lis.Accept 阻塞,等待请求

客户端调用过程

Dial() 创建一个链接
  |- DialContext  可以设置context来控制连接超时等信息
  |- inserure 是否加密, 如果设置了证书认证,接下来
NewSearchServiceClient 创建一个客户端
  |- Search proto生成的自定义的方法
    |- Invoke 发送RPC请求然后等待响应并返回
      |- invoke 发送接收数据
        |- newClientStream 实例化客户端流,设置最大发送接收的信息大小
        |- SendMsg 发送数据
          |- prepareMsg 准备请求的数据,涉及编码 压缩 设置头信息
            |- encode  序列化数据
            |- compress 压缩数据
            |- msgHeader 增加5个字节的header
            |- 比较发送的数据是否大于预设的最大数据大小,超出则报错返回
            |- withRetry 
              |- sendMsg 使用withRetry包装发送数据的方法,以便失败后可以重试
                |- a.t.Write 写入数据
        |- RecvMsg 接收响应的数据
          |- withRetry  重试
            |- recvMsg  接收数据
              |- recv   接收两次数据 后一次error或者io.EOF
                |- recvAndDecompress 接收并且解压数据,接收的数据要小于等于设置的最大的消息大小
                  |- recvMsg io.Reader接口读取数据
                |- Unmarshal 反序列化字节到指定结构体
  

服务端处理请求并返回响应

服务端接收到请求后,handleRawConn就会开始异步的处理这些请求

handleRawConn 启动一个goroutinue来处理请求,防止阻塞其他请求
  |- useTransportAuthenticator 获取加密过的链接,加密信息
  |- newHTTP2Transport http2握手链接
  |- serveStreams服务端流
  |- handleStream 执行调用方调用的方法
    |- processUnaryRPC 处理非流传输的调用
       |- RecvCompress 返回压缩算法信息
       |- SetSendCompress 设置stream的压缩算法
       |- recvAndDecompress 接收数据并反序列化
       |- md.Handler 执行请求的方法
       |- sendResponse 发送响应数据
       |- WriteStatus 写入状态数据
    |- processStreamingRPC 处理流式传输的调用

以上只涉及简单的gRPC调用过程分析,未涉及流式调用的分析不过也是大同小异