How do I make a Go gRPC work with standard IO on t

2019-08-15 10:45发布

问题:

I am a freshman of gRPC, and here is my problem. I'm trying to write a service to expose myOwnService into a gRPC service per the following service method:

rpc HighFive (stream HighRequest) returns (stream HighReply) {}

The server-side code is as follows:

func (s *server) HighFive(stream pb.Greeter_HighFiveServer) error {    
    // Oops, don't know how to do here ...
    myOwnService(stdin io.ReadCloser, stdout io.WriteCloser)
    return nil
}

func myOwnService(stdin io.ReadCloser, stdout io.WriteCloser) error {    
    // read input from stdin, do something, the  write result to stdout
    ...
    return nil
}

As you can see above, I have no idea how to make stream work with io.Reader and io.Writer in my original service, so that the caller of the HighFive gRPC service can read and write data just like calling myOwnService normally.

[Update] My current messages are like this, but you can change them if necessary:

message HighRequest {
  bytes content  = 1;
}

message HighReply {
  bytes content  = 1;
}

回答1:

Per the gRPC Basics tutorial section on Bidirectional streaming RPC, each call to your stream parameter's Recv method will give you a decoded HighRequest message, not a byte stream, as you're expecting for your myOwnService function.

Now, if your HighRequest message contains a field of types bytes or string, you may wish to feed that field's content into myOwnService as the stdin parameter by wrapping the raw []byte value via bytes.NewReader.

I see, though, that myOwnService demands an io.ReadCloser. I don't know why you'd expect myOwnService to close its input parameter, but I'll trust you well enough that you need it to then recommend using ioutil.NopCloser to satisfy that demand trivially.

Sketching:

// Next tag: 2
message HighRequest {
  bytes content = 1;
}

func (s *server) HighFive(stream pb.Greeter_HighFiveServer) error {
  for req, err := stream.Recv(); {
    if err != nil {
      if err == io.EOF {
        return nil
      }
      return err
    }
    in := ioutil.NopCloser(bytes.NewReader(req.Content))
    out := /* ... */
    if err := myOwnService(in, out); err != nil {
      return err
    }
  }
}