grpc 源码阅读 —— 客户端


Service定义

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

客户端代码

...
func main() {
	conn, ... := grpc.Dial(address, ...)
    c := pb.NewGreeterClient(conn)
    c.SayHello(..., &pb.HelloRequest{Name: name})
}

grpc.Dial()返回了一个grpc.ClientConn对象(一个抽象的网络连接)conn,然后将conn注入到helloworld.greeterClient对象(由proto文件生成)c,最终通过c发起一次RPC调用SayHello

一次RPC调用经过了哪些代码层次?

helloworld.greeterClient.SayHello()只是对grpc.ClientConn.Invoke()的简单包装,指定了HelloRequestHelloReply为输入输出参数。

每次的grpc.ClientConn.Invoke()调用,过程中会创建一个临时的grpc.clientStream对象,然后依次调用grpc.clientStream.SendMsg()grpc.clientStream.RecvMsg()便完成了一次RPC调用,随后grpc.clientStream对象的生命周期结束。

grpc.ClientConn层次之下是grpc.csAttempt,含义为一次RPC调用的“意图”,grpc.csAttempt这一层次的封装主要负责RPC的失败重试。每次通过grpc.csAttempt对象发起RPC通信,如若RPC通信失败,则会重新构建grpc.csAttempt(重新获取下层网络连接),然后进行重试。

grpc.clientStream.SendMsg()实际上是调用grpc.csAttempt.sendMsg(),外加失败重试处理。近似的grpc.clientStream.RecvMsg()对应grpc.csAttempt.recvMsg()

grpc.csAttempt层次之下是transport.http2Clienttransport.Streamtransport.Stream负责对transport.http2Client的分流处理。transport.http2Client可被多个RPC Client复用,读写数据依据stream id分发到不同的transport.Stream

最后transport.http2Client之下是http2协议http2.Framer这里不做赘述。

调用层次树状图

helloworld.greeterClient.SayHello()
	grpc.ClientConn.Invoke()
		grpc.clientStream = grpc.newClientStream()
			grpc.csAttempt = grpc.clientStream.newAttemptLocked()
				transport.http2Client = transport.newHTTP2Client()
					http2.Framer = http2.NewFramer()
				transport.Stream = transport.http2Client.NewStream()
		grpc.clientStream.SendMsg()
			grpc.csAttempt.sendMsg()
				transport.http2Client.Write(transport.Stream)
					http2.Framer.w.Write()
		grpc.clientStream.RecvMsg()
			grpc.csAttempt.recvMsg()
				transport.Stream.Read()
					http2.Framer.r.Read()


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM