I wonder how does SignalR client receive messages from server after connection has been established? I mean, what happens on the client side internally after Connection.Send(message) method has been invoked?
From reading .NET client code I've found that public event Action<string> Received in Connection class is responsible for receiving messages, but I can't find how it is implemented. I need to know how it works internally because I want to write my own client on Java.
You can read the entire source of signalR on github: https://github.com/SignalR/SignalR
In particular, you can find the source for PersistentConnection - at
https://github.com/SignalR/SignalR/blob/master/src/Microsoft.AspNet.SignalR.Core/PersistentConnection.cs
Related
When using server-sent events, how does server communicate to browser that there won't be more events and that it should close the sse connection?
Is this a part of the protocol or should this be implemented by passing hint in normal event to the client that it can close event source ?
The server-sent events is yet another streaming technique which is one of ways of Comet. To stop streaming data, just close the connection in server. You don't need to let client call close method of EventSource instance.
FYI, the following links show that how Cettia streaming transport backed by server-sent events implements to close connection. (Note that I'm an author of Cettia)
Java server - https://github.com/cettia/cettia-java-server/blob/1.0.0-Beta1/server%2Fsrc%2Fmain%2Fjava%2Fio%2Fcettia%2Ftransport%2Fhttp%2FHttpTransportServer.java#L358
JavaScript client - https://github.com/cettia/cettia-javascript-client/blob/1.0.0-Beta1/cettia.js#L884-L886
Edit
For that issue, I added es.close within es.onerror.
From the introduction on gRPC:
In gRPC a client application can directly call methods on a server application on a different machine as if it was a local object, making it easier for you to create distributed applications and services. As in many RPC systems, gRPC is based around the idea of defining a service, specifying the methods that can be called remotely with their parameters and return types. On the server side, the server implements this interface and runs a gRPC server to handle client calls. On the client side, the client has a stub that provides exactly the same methods as the server.
The above paragraph talks about a client and a server, with the former being the one who is invoking methods to the other. What am I wondering is: can the server-end of the connection invoke methods that have been registered on the client?
No, a server cannot invoke calls on the client. gRPC works with HTTP, and HTTP has not had such semantics in the past.
There has been discussion as to various ways to achieve such a feature, but I'm unaware of any work having started or general agreement on a design. gRPC does support bidirectional streaming, which may get you some of what you need. With bidirectional streaming the client can respond to messages from server, but the client still calls the server and only one type of message can be sent for that call.
The protocol does not implement it, but you may pretend this situation.
Define a server method that returns a stream of a ServerRequest message:
import "google/protobuf/any.proto";
service FullDuplex {
rpc WaitRequests (google.protobuf.Any) returns (stream ServerRequest);
}
message ServerRequest {
float someValue = 1;
float anotherAnother = 1;
}
ServerRequest may be an Oneof, so your may receive different types of server requests.
If you need that your client sends back a response for each request, you may create a stream from your client to the server, but you will need to implement a logic in your server side that triggers a timeout waiting for that response.
service FullDuplex {
rpc WaitRequests (stream ClientResponse) returns (stream ServerRequest);
}
What you can do is start a HTTP server in both processes and use clients at each end to initiate communication. There's a bit of boilerplate involved and you have to design a simple handshaking protocol (one end registers with the other, advertising its listen address) but it's not too much work.
Abstract
Hi, I was pondering whether it is possible to loose a message with SignalR. Suppose client disconnects but eventually reconnects in a short amount of time, for example 3 seconds. Will the client get all of the messages that were sent to him while he was disconnected?
For example let's consider LongPolling transport. As far as I'm aware long polling is a simple http request that is issued in advance by the client in order to wait a server event.
As soon as server event occurs the data getting published on the http request which leads to closing connection on issued http request. After that, client issues new http request that repeats the whole loop again.
The problem
Suppose two events happened on the server, first A then B (nearly instantly). Client gets message A which results with closing http connection. Now to get message B client has to issue second http request.
Question
If the B event happened while the client was disconnected from the server and was trying to reconnect.
Will the client get the B message automatically, or I have to invent some sort of mechanisms that will ensure message integrity?
The question applies not only to long-polling but to general situation with client reconnection.
P.S.
I'm using SignalR Hubs on the server side.
EDIT:
I've found-out that the order of messages is not guaranteed, I was not able to make SignalR loose messages
The answer to this question lies in the EnqueueOperation method here...
https://github.com/SignalR/SignalR/blob/master/src/Microsoft.AspNet.SignalR.Core/Transports/TransportDisconnectBase.cs
protected virtual internal Task EnqueueOperation(Func<object, Task> writeAsync, object state)
{
if (!IsAlive)
{
return TaskAsyncHelper.Empty;
}
// Only enqueue new writes if the connection is alive
Task writeTask = WriteQueue.Enqueue(writeAsync, state);
_lastWriteTask = writeTask;
return writeTask;
}
When the server sends a message to a client it calls this method. In your example above, the server would enqueue 2 messages to be sent, then the client would reconnect after receiving the first, then the second message would be sent.
If the server queues and sends the first message and the client reconnects, there is a small window where the second message could attempt to be enqueued where the connection is not alive and the message would be dropped at the server end. Then after reconnect the client wouldn't get the second message.
Hope this helps
If "OnConnected" is raised when the 1st time we connect to our website, when will "OnReconnected" happen?
1) Suppose someone is connected to the network and suddenly the network isn't available and soon it recovers, so OnReconnected happens?
2) Any other special that will make OnReconnted happen?
Thanks!
The Signalr documentation on Understanding and Handling Connection Lifetime Events in SignalR should have all the information you need.
Generally speaking OnReconnected will fire any time the SignalR client automatically reconnects to the SignalR server after it has lost its connection for any reason. These reasons can include network issues, the server restarting, etc...
The SignalR client will stop attempting to automatically reconnect to the server if it is unable to successfully do so within the DisconnectTimeout. If this happens, and you want to reestablish a connection, you will be required to manually restart the client by calling start() after the client becomes disconnected. If you manually restart the client by calling start(), OnConnected will be called instead of OnReconnected and the client will receive a new connection id.
If I send a messag using SignalR, is it possible that the client does not receive the message? How can you verify if any errors apeared in the communication? Iam thinking of sending a message back to server after the server notification was sent, but is there any better way?
Yes, it's possible that the client doesn't receive the message. SignalR keeps messages in memory for 30 seconds (by default, you can tweak that or use a persistent message bus), so if the client isn't connected for whatever reason and this timeout passes the client will miss the message. Note that if he reconnects within this period he receives all messages he hasn't got yet, including those that were sent when he was disconnected.
I don't know if SignalR provides a way of telling you when a broadcast failed, so it might be safer to just send an acknowledgement back to the server.
As long as the client is connected, it will get the messages. You can subscribe to connection state changes in client side code. In server side code you can implement IConnected and IDisconnect interfaces to handle the Connect, Disconnect, and Reconnect events.