gRPC阅读日记(七)客户端的RPC构建
Client-side streaming RPC
客户端的流式方法RecordRoute跟服务端的相似,除了我们只传了context,获取到RouteGuide_RecordRouteClient流对象回来。流可以让我们既可以写也可以读消息。
// Create a random number of random points r := rand.New(rand.NewSource(time.Now().UnixNano())) pointCount := int(r.Int31n(100)) + 2 // Traverse at least two points var points []*pb.Point for i := 0; i < pointCount; i++ { points = append(points, randomPoint(r)) } log.Printf("Traversing %d points.", len(points)) stream, err := client.RecordRoute(context.Background()) if err != nil { log.Fatalf("%v.RecordRoute(_) = _, %v", client, err) } for _, point := range points { if err := stream.Send(point); err != nil { log.Fatalf("%v.Send(%v) = %v", stream, point, err) } } reply, err := stream.CloseAndRecv() if err != nil { log.Fatalf("%v.CloseAndRecv() got error %v, want %v", stream, err, nil) } log.Printf("Route summary: %v", reply)
RouteGuide_RecordRouteClient有Send方法,可以发送请求给server,一旦我们用Send发完了请求,让gRPC知道我们已经结束写阶段,希望获取响应了,就能从CloseAndRecv()返回的err得治RPC状态。如果状态是nil,那么CloseAndRecv()返回的就是有效的服务响应。
Bidirectional streaming RPC
双向流RPC RouteChat(),使用了goroutine去对steam做读,然后主的goroutine去做写,最后client端洗完了,调用了CloseSend()最后还做了线程同步,等goroutine都结束。
stream, err := client.RouteChat(context.Background()) waitc := make(chan struct{}) go func() { for { in, err := stream.Recv() if err == io.EOF { // read done. close(waitc) return } if err != nil { log.Fatalf("Failed to receive a note : %v", err) } log.Printf("Got message %s at point(%d, %d)", in.Message, in.Location.Latitude, in.Location.Longitude) } }() for _, note := range notes { if err := stream.Send(note); err != nil { log.Fatalf("Failed to send a note: %v", err) } } stream.CloseSend() <-waitc
外加再补充一句,客户端和服务端请求和响应的消息顺序一直是有序的,但是他们处理消息的顺序可以in any orider。这句话基础教程里提了好多次了
下一期讲gRPC basics tutorial的总结, respect!!!
Reference
https://grpc.io/docs/languages/go/basics/