gRPC阅读日记(四)Client-side streaming

2022-03-05  本文已影响0人  糖醋沼跃鱼

gRPC阅读日记(四)

Client-side streaming RPC

今天介绍的是比较复杂的RPC了,Client-side streaming 方法RecordRoute,服务端处理来自客户端的流式请求,这次,client会发送连续的Point消息请求,然后服务端返回单次响应RouteSummary,响应带有行程中的信息。从下方的例子中可以看到,这次方法不需要请求参数,而是用了RouteGuide_RecordRouteServer流,可以同时读写消息,并且可以通过Recv()来接收客户端消息,然后返回单个响应通过SendAndClose()方法

func (s *routeGuideServer) RecordRoute(stream pb.RouteGuide_RecordRouteServer) error {
  var pointCount, featureCount, distance int32
  var lastPoint *pb.Point
  startTime := time.Now()
  for {
    point, err := stream.Recv()
    if err == io.EOF {
      endTime := time.Now()
      return stream.SendAndClose(&pb.RouteSummary{
        PointCount:   pointCount,
        FeatureCount: featureCount,
        Distance:     distance,
        ElapsedTime:  int32(endTime.Sub(startTime).Seconds()),
      })
    }
    if err != nil {
      return err
    }
    pointCount++
    for _, feature := range s.savedFeatures {
      if proto.Equal(feature.Location, point) {
        featureCount++
      }
    }
    if lastPoint != nil {
      distance += calcDistance(lastPoint, point)
    }
    lastPoint = point
  }
}

在方法中可以看到,RouteGuide_RecordRouteServer的Recv()方法一直重复阅读来自客户端的请求,在具体一点,Recv()一直获取来自请求流中的单个point消息直到读取不到更多的消息。服务端必须检查Recv()方法的error,如果error等于nil,证明仍然需要读取消息,如果error等于io.EOF证明已经读取完毕了。服务器就可以返回RouteSummary。如果error既不是读取完毕io.EOF也不是nil则返回该错误,因为gRPC层会将它翻译成RPC状态并返回给客户端。

Bidirectional streaming RPC

来看最后一种双向流RPC的实现RouteChat()

func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error {
  for {
    in, err := stream.Recv()
    if err == io.EOF {
      return nil
    }
    if err != nil {
      return err
    }
    key := serialize(in.Location)
                ... // look for notes to be sent to client
    for _, note := range s.routeNotes[key] {
      if err := stream.Send(note); err != nil {
        return err
      }
    }
  }
}

这次使用了RouteGuide_RouteChatServer流,在上一个客户端请求流式用例中,可以用来读写信息,这次我们通过方法的流来返回值的同时,客户端也仍然在像流中写消息。

从语法上也跟client-streaming方法很相似,除了服务端需要使用流的send()方法,而不是SendAndClose(),因为需要用俩写多重响应。尽管每一端总是能获取到按照他们写顺序的消息,但客户端和服务端都还能不根据顺序来读去消息,流的操作是完全独立的。

上一篇下一篇

猜你喜欢

热点阅读