grpc-dotnet
grpc-dotnet copied to clipboard
Client-side RPC
Hello, I'm planning to use gRPC for my next project, but as far as I've understood only RPC on the server are supported. The situation is that I want to connect multiple clients to a gRPC server and then let the server call methods on the connected clients. So basically, the reverse of current gRPC functionality. What would be the easiest way to achieve this behavior? Also, is there a way for the server to list all connected clients and address each one individually?
For your first question I am not sure if what you're describing is possible at least the way you've described it. gRPC supports duplex streaming so you can communicate between client and server in both directions. That way you can selectively send messages to different clients and then how each client processes these messages is up to you.
Regarding your second question - When you call a RPC on the server, server-side you can add the caller to a concurrent dictionary that keeps some identifier for it as key and its IServerStreamWriter
response stream as value. Then you would have a collection of all subscribers and can selectively write messages to them. Of course, you would also have to remove the caller from the dictionary once the RPC has been completed.
Here is an article with some code examples that might help you: https://damienbod.com/2019/03/25/grpc-bi-directional-streaming-with-razor-pages-and-a-hosted-service-grpc-client/
There are many problems making a server call a client like firewalls and NAT addressing.
A better solution is for clients to connect to the server and establish an ongoing connection. The server can then send messages to the client on that connection.
@VasilSirakov Thanks for your reply, by using duplex connections and streaming I would then have to build my own protocol on top of gRPC which is actually what I would like to avoid.
@JamesNK I think you've misunderstood me. Sorry I'll try to explain it better. The client still establishes the connection to the server. So firewalls and port forwarding stuff is not a problem. I just want to call methods on the clients from the server (given an established connection) in a way that's as elegant as doing the calls now on the server. Is there no other way than using the streaming?
You may find issue https://github.com/grpc/grpc/issues/14101 about "tunneling" interesting. (This is the repository for the C code that drives most of the gRPC implementations out there today. Notably, grpc-dotnet doesn't use this code, but it needs to interoperate with it.)
There are unresolved design issues in this space, but that issue also talks about some approaches that others have used to approximate something like what you're looking for, including
- an app-specific streaming protocol,
- using a third-party proxy tool,
- hooks available in some implementations for binding a gRPC channel to an already open TCP/HTTP connection, and
- techniques like running gRPC over SSH port forwarding.
Is there no other way than using the streaming?
Streaming is the only way I know how.
- The client establishes a server streaming call
- The client listens for incoming messages from the call and acts on them
- When the server wants to "invoke" the client it sends a message
In gRPC there is no state on the server of all the clients that are listening. If you want to send a message to all clients (i.e. broadcast the message) then you'll need to implement that yourself.
SignalR on the other hand is stateful, and records all the clients connected to a hub. That makes broadcasting a message to all clients easier.