Implementing a robust and efficient RPC system - networking

I need to have a server which is able to call functions on the client. I always used RPC's in different networking game API's but I never implemented it by myself.
How would I do it?
My naive approach would be:
connect client to the server:
server
fn update_position_client(){
unique_id = 1;
send.to_client(unique_id);
}
client
while recv_messages {
if id == 1
update_position();
}
Is this how I would do it?

This works if you only have a few messages that you want to send, and if the data basically known. To be more robust, you would want to have the ability to dynamically add/remove messages that can be called, and figure out how to look up the methods to be called when RPC is called.
Assuming you want this to be completely transparent to the user, what typically happens in this case is that when the a message is sent, the RPC library will wait until there's a response back. Assuming bi-directional capabilities, what normally happens is that there's a single thread that listens for data. If an RPC message comes in, this thread will figure out what to do with the message, i.e. what method to call in your(local) address space and with what parameters you want to call it with. When you send an RPC message out, the thread that you sent the message out on is blocked(probably with a semaphore) until the return message comes back, at which point your local thread is unblocked and allowed to continue.
A Linux-specific RPC library you could look at would be DBus.

Related

Grpc C++: How to wait until a unary request has been sent?

I'm writing a wrapper around gRPC unary calls, but I'm having an issue: let's say I have a ClientAsyncResponseReader object which is created and starts a request like so
response_reader_ = std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
grpc::internal::ClientAsyncResponseReaderFactory<ResponseType>::Create(
channel.get(), completion_queue, rpc_method, &client_context_, request, true
)
);
response_reader_->Finish(
response_sharedptr_.get(), status_sharedptr_.get(), static_cast<void*>(some_tag)
);
// Set a breakpoint here
where all of the arguments are valid.
I was under the impression that when the Finish call returned, the request object was guaranteed to have been sent out over the wire. However by setting a breakpoint after that Finish() call (in the client program, to be clear) and inspecting my server's logs, I've discovered that the server does not log the request until after I resume from the breakpoint.
This would seem to indicate that there's something else I need to wait on in order to ensure that the request is really sent out: and moreover, that the thread executing the code above still has some sort of role in sending out the request which appears post-breakpoint.
Of course, perhaps my assumptions are wrong and the server isn't logging the request as soon as it comes in. If not though, then clearly I don't understand gRPC's semantics as well as I should, so I was hoping for some more experienced insight.
You can see the code for my unary call abstraction here. It should be sufficient, but if anything else is required I'm happy to provide it.
EDIT: The plot thickens. After setting a breakpoint on the server's handler for the incoming requests, it looks like the call to Finish generally does "ensure" that the request has been sent out: except for the first request sent by the process. I guess that there is some state maintained either in grpc::channel or maybe even in grpc::completion_queue which is delaying the initial request
From the documentation
response_reader_ = std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
grpc::internal::ClientAsyncResponseReaderFactory<ResponseType>::Create(
channel.get(), completion_queue, rpc_method, &client_context_, request, true
)
);
This will start a call and write the request out (start=true). This function does not have a tag parameter. So there is no way the completion queue can notify when the call start is finished. Calling an RPC method is a bit complicated, it basically involves creating the network packet and putting it in the wire. It can fail if there is a transient failure of the transport or the channel completely gone or the user did something stupid. Another thing, why we need the tag notification is that the completion queue is really a contention point. All RPC objects talk to this, it can happen completion queue is not free and the request is still pending.
response_reader_->Finish(
response_sharedptr_.get(), status_sharedptr_.get(), static_cast<void*>(some_tag)
This one will request the RPC runtime to receive the server's response. The output is when the server response arrives, then the completion queue will notify the client. At this point. we assume that there is no error on the client side, everything okay and the request is already in flight. So the status of Finish call will never be false for unary rpc.
This would seem to indicate that there's something else I need to wait on in order to ensure that the request is really sent out: and moreover, that the thread executing the code above still has some sort of role in sending out the request which appears post-breakpoint.
Perhaps, you want to reuse the request object(I did some experiments on that). For me, I keep the request object in memory till the response arrives. There is no way to guarantee that the request object won't be required after the create call.

Timeout for broadcasting message using SignalR

I am using SignalR for the 1st time in my asp.net c# web app.
I am using HTML 5 and JavaScript for my client web page.
In essence whenever my server has an image to 'push' to my clients it does so. Sometimes this can be quite frequent.
Now, I imagine during a 'busy' period' my client(s) could be 'over-whelmed' by the data being pushed by my server?
How does my server know that the message has been recieved by my client (or not) and then proceed to send the next one?
SignalR doesn't provide a built-in way to wait for a client to receive a message. This would be very difficult to do in the general case where someone might be using Clients.All, and clients might be connecting/reconnecting/disconnecting at the time the message is sent.
However, it is possible to manually acknowledge that you have received a message on the client (perhaps by calling some hub method on the server), and then continue to send the next message once the acknowledgement (ACK) for the previous one has been received.

handling XMLHttpRequest abort on asp.net

I use asynchronous XMLHttpRequest to call a function in ASP.net web service.
When I call an abort method on the XMLHttpRequest, after the server has received the request and processing it, the server continues processing the request.
Is there a way to stop the request processing on the server?
Generally speaking, no, you can't stop the request being processed by the server once it has started. After all, how would the server know when a request has been aborted?
It's like if you navigated to a web page but browsed to another one before the first one had loaded. That initial request will, at least to some extent (any client-side work will of course not take place), be fulfilled.
If you do wish to stop a long-running operation on the server, the service that is being invoked will need to be architected such that it can support being interrupted. Some psuedo code:
void MyLongRunningMethod(opId, args)
{
work = GetWork(args)
foreach(workItem in work)
{
DoWork(workItem)
//Has this invocation been aborted?
if(LookUpSet.Contains(opId))
{
LookUpSet.Remove(opId)
return
}
//Or try this:
if(Response.IsClientConnected)
{
HttpContext.Current.Response.End();
return;
}
}
}
void AbortOperation(opId)
{
LookUpSet[opId] = true
}
So the idea here is that MyLongRunningMethod periodically checks to see if it has been aborted, returning if so. It is intended that opId is unique, so you could generate it based on the session Id of the client appended with the current time or something (in Javascript, new Date().getTime() will get you the number of milliseconds since the epoch).
With this sort of approach, the server must maintain state (the LookUpSet in my example), so you will need some way of doing that, such as a database or just storing it in memory. The service will also need to be architected such that calling abort does not leave things in a non-working state, which of course depends very heavily on what it does.
The other really important requirement is that the data can be split up and worked on in chunks. This is what allows the service to be interruptable.
Finally, if some operation is to be aborted, then AbortOperation must be called - simply aborting the XMLHttpRequest invocation won't do help as the operation will continue until completion.
Edit
From this question: ASP.Net: How to stop page execution when browser disconnects?
You could also check the Response.IsClientConnected property to try and determine whether the invocation had been aborted.
Generally speaking, the server isn't going to know that a client has disconnected until it attempts to send data to it. See Best practice to detect a client disconnection in .NET? and Instantly detect client disconnection from server socket.
As nick_w wrote you can't stop the request being processed by the server once it has started. But there is ability to implement solution which will give you ability to cancel server task. Dino Esposito has several great articles about how such things can be implemented:
Canceling Server Tasks with ASP.NET AJAX
And in the following articles to implement pooling to server Dino Esposito describes how to use SignalR library:
Build a Progress Bar with SignalR;
Long Polling and SignalR
So if you really need to cancel some task on server these articles can be used as starting point to implement required solution.

Network protocol implementation like QNAM with delayed processing of requests

I need to implement network protocol working over tcp that basically works next way:
There is requests that are pushed and answers that are read (only one party can initiate request).
I do want to implement it in a way like QNetworkAccessManager: when "requestst is sent, QNAM return a pointer to reply, once requests is served - there is a signal and the result can be used from "reply" object.
I do want to implement it without multithreading.
The major problem is next:
If socket is not connected I have 3 options:
1) return an error (returning null pointeter to reply object is like returning error)
2) emit "finish" from inside "sendRequest" (this is most evil approach)
3) return "reply" from "sendRequest" and later emit signal that request failed. (most wanted)
I really like 3-rd option but the only way I see now is to use timer with 1 ms one shot call - that basically looks like wrong path to implement such thing,
How can I make delayed execution of slot (with passing some parameter like coockie to request)?
It will be good if there is a way to send request delayed as well (like push request to queue, return from call with "reply" object and after then send actual request over network).
All this looks like dealing with event - but I am not sure how best to deal with this subject.
What is the best practice to implement such protocol?
Any advice?

SignalR: Why choose Hub vs. Persistent Connection?

I've been searching and reading up on SignalR recently and, while I see a lot of explanation of what the difference is between Hubs and Persistent Connections I haven't been able to get my head around the next level, which is why would I choose one approach over the other?
From what I see in the Connection and Hubs section it seems that Hubs provide a topic system overlaying the lower-level persistent connections.
From the highly up-voted comment below:
Partially correct. You can get topics or groups in persistent connections as well. The big difference is dispatching different types of messages. For example you have different kinds of messages and you want to send different kinds of payloads. With persistent connections you have to embed the message type in the payload (see Raw sample) but hubs gives you the ability to do RPC over a connection (lets you call methods on on the client from the server and from the server to the client). Another big thing is model binding. Hubs allow you to pass strongly typed parameters to methods.
The example used in the documentation uses a chat room metaphor, where users can join a specific room and then only get messages from other users in the same room. More generically your code subscribes to a topic and then get just messages published to that topic. With the persistent connections you'd get all messages.
You could easily build your own topic system on top of the persistent connections, but in this case the SignalR team did the work for you already.
The main difference is that you can't do RPC with PersistentConnection, you can only send raw data. So instead of sending messages from the server like this
Clients.All.addNewMessageToPage(name, message);
you'd have to send an object with Connection.Broadcast() or Connection.Send() and then the client would have to decide what to do with that. You could, for example, send an object like this:
Connection.Broadcast(new {
method: "addNewMessageToPage",
name: "Albert",
message: "Hello"
});
And on the client, instead of simply defining
yourHub.client.addNewMessageToPage = function(name, message) {
// things and stuff
};
you'd have to add a callback to handle all incoming messages:
function addNewMessageToPage(name, message) {
// things and stuff
}
connection.received(function (data) {
var method = data.method;
window[method](data.name, data.message);
});
You'd have to do the same kind of dispatching on the server side in the OnReceived method. You'd also have to deserialize the data string there instead of receiving the strongly typed objects as you do with hub methods.
There aren't many reasons to choose PersistentConnection over Hubs. One reason I'm aware of is that it is possible to send preserialized JSON via PersistentConnection, which you can't do using hubs. In certain situations, this might be a relevant performance benefit.
Apart from that, see this quote from the documentation:
Choosing a communication model
Most applications should use the Hubs API. The Connections API could
be used in the following circumstances:
The format of the actual message sent needs to be specified.
The developer prefers to work with a messaging and dispatching model
rather than a remote invocation model.
An existing application that uses a messaging model is being ported to use SignalR.
Depending on your message structure, you might also get small perfomance benefits from using PersistentConnection.
You may want to take a look at the SignalR samples, specifically this here.
There are two ways to use SignalR: you can access it at a low level by overriding its PersistentConnection class, which gives you a lot of control over it; or you can let SignalR do all of the heavy lifting for you, by using the high level ‘Hubs’.
Persistent Connection is a lower level API, you can perform actions on more specific time when the connection is opened or closed, in most applications the Hub is the best choice
There are three major points to consider when comparing these two:
Message Format
Communication model
SignalR customization
With hubs message formatting is basically handled from you but with persistent connections the message is raw and has be tokenized and parsed back and forth. If the message size is important then also note that the payload of a persistent connection is much less that that of a hub.
When it comes to the communication model persistent connections basically have a function for sending and receiving messaging while hubs take a remote procedure call model with unique function per requirement.
When it comes to customization since persistent connections are more low level they may give you more control over customization.

Resources