chinmay
chinmay

Reputation: 859

Whats the golang's `stream.Send()` equivalent in python grpc clients in bidirectional stream?

Lets say below is the proto for bi-directional stream

service RouteGuide {
  // A Bidirectional streaming RPC.
  //
  // Accepts a stream of RouteNotes sent while a route is being traversed,
  // while receiving other RouteNotes (e.g. from other users).
  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}

Go defines an interface to send & rec messages inside a bidirectional stream from server to client & vice-versa : go interface. But I couldn't find the same in Python, to send the response inside the stream without making an additional RouteChat call.

Also the example provided doesnt talk about sending a request back from client

How can we send the request back to server from client from python grpc clients with in the same stream?


def generate_messages():
    messages = [
        make_route_note("First message", 0, 0),
        make_route_note("Second message", 0, 1),
        make_route_note("Third message", 1, 0),
        make_route_note("Fourth message", 0, 0),
        make_route_note("Fifth message", 1, 0),
    ]
    for msg in messages:
        print("Sending %s at %s" % (msg.message, msg.location))
        yield msg


def guide_route_chat(stub):
    responses = stub.RouteChat(generate_messages())
    for response in responses:
        print("Received message %s at %s" % (response.message, response.location))
    

Upvotes: 2

Views: 215

Answers (3)

H Soora
H Soora

Reputation: 67

For following proto:

syntax = "proto3";
package Streaming;

service Streaming{
    rpc RpcFunction(stream Request) returns (stream Response) {}
}

message Request {
    oneof stream_input {
        bytes data = 1;
    }
}
message Response {
    oneof stream_output {
        bytes data = 1;
    }
}

You can send-recv message async using following function:

async with grpc.aio.insecure_channel("0.0.0.0:8001", 
            options=[ ('grpc.max_send_message_length', MAX_MESSAGE_LENGTH),
                      ('grpc.max_receive_message_length', MAX_MESSAGE_LENGTH)]
    ) as channel:
    try:
        await asyncio.wait_for(channel.channel_ready(), timeout=15)
    except asyncio.TimeoutError:
        sys.exit('Error connecting to server')
    stub = streaming_pb2_grpc.StreamingStub(channel)
    stream = stub.RpcFunction()

    for itr in range(0, len(msg)):
        request = streaming_pb2.Request(data=msg[itr].tobytes())
        await stream.write(request)
        response = await stream.read()
        print(response.data.decode("utf-8"))

Upvotes: 0

Richard Belleville
Richard Belleville

Reputation: 1620

For the sync stack (i.e. not asyncio), there is no API like this. Instead, you're expected to pass in an iterator of your outgoing requests. See this previous SO answer for an example of that.

The asyncio API however does have a write/read API that is very similar to Go's.

Upvotes: 1

Syed Momin Naqvi
Syed Momin Naqvi

Reputation: 35

You can use the same stream object to send and receive messages in a bidirectional gRPC. To send a message back to the server from the client, you can simply call the stream.write() method on the stream object with the message you want to send.

You can change this function of yours to be this way:

def guide_route_chat(stub):
    stream = stub.RouteChat(generate_messages())
    for response in stream:
        print("Received message %s at %s" % (response.message, response.location))
        # Send a message back to the server
        request = RouteNote()
        request.message = "Sending message back to server."
        request.location.latitude = 37.7749
        request.location.longitude = -122.4194
        stream.write(request)

It is important to keep in mind that the stream needs to be in active state for you to be able to send messages back. You can check this via stream.isactive()

Upvotes: -1

Related Questions