The System.Net.TcpClient object can only connect to an endpoint once. If the client forces the disconnect, then it is clear that the client needs to be replaced. If the server cancels the connection, then it is possible to test the connection and know when it is no longer connected. However once it has been disconnected, I cannot see any property or method that differentiated the disconnected and used client from a disconnected and fresh client.
What is the correct way to test for a disconnected and used client?
Related
All,
I am using SignalR (.net 6) and have couple of questions about SignalR Connections (specifically SignalR connections that use web sockets):
Q #1)
If the SignalR client crashes, will SignalR server dispose the underlying connection automatically for me (and the OnDisconnectedAsync() event will be fired)?
The idea is to dispose client resources (on the server, resource ex: NHibernate session) that are tied to each connection.
My Tests Indicate (on local machine, both server and client):
I tried to simulate this scenario where I had a running client which then I shut down with Task manager and the minute Windows released resources for the process, the SignalR server somehow detected that connection was lost and released the connection and OnDisconnectedAsync() was called. I am not sure if my test was sufficient for this use case (client crash). I am curious of how did the server know, was it the fact the maybe the finalizer for client connection ran?
Q #2) If the current connection between client and server is broken or interrupted and SignalR needs to reconnect, and it successfully reconnects, does it use the same connection (with the same connection ID/same web socket) or does it attempt create new connection (tied to a new web socket)?
https://learn.microsoft.com/en-us/aspnet/core/signalr/configuration?view=aspnetcore-6.0&tabs=dotnet
The server considers the client disconnected if it hasn't received a message (including keep-alive) in this interval. It could take longer than this timeout interval for the client to be marked disconnected due to how this is implemented. The recommended value is double the KeepAliveInterval value.
It assigns a new connection id. Consider using other data to track which user is it, eg. Checking in the on connect and on disconnect methods.
https://learn.microsoft.com/en-us/aspnet/core/signalr/groups?view=aspnetcore-6.0
What I wish to achieve:
When establish a connection, prevent user from sending any message until the connection had finished all the setup (with STUN/TURN server etc)
When there is a sudden disconnect, prevent the user from sending any message until the connection is re-established.
My best guess is either one of the event handler below will do the trick, but I don't know which one, and don't know what are the differences between the two.
onconnectionstatechange()
oniceconnectionstatechange()
oniceconnectionstatechange doesn't include the establishment of the DTLS handshake on top of the ice connection.
Use onconnectionstatechange to detect when the connection is fully established and also to detect disconnections.
I have a chat implementation working with CometD.
On front end I have a Client that has a clientId=123 and is talking to VirtualMachine-1
The longpolling connection between the VirtualMachine-1 and the Client is done through the clientId. When the connection is established during the handshake, VirtualMachine-1 registers the 123 clientId as it's own and accepts its data.
For some reason, if VM-1 is restarted or FAILS. The longpolling connection between Client and VM-1 is disconnected (since the VirtualMachine-1 is dead, the heartbeats would fail, thus it would become disconnected).
In which case, CometD loadBalancer will re-route the Client communication to a new VirtualMachine-2. However, since VirtualMachine-2 has different clientId it is not able to understand the "123" coming from the Client.
My question is - what is the cometD behavior in this case? How does it re-route the traffic from VM-1 to a new VM-2 to successfully go through handshaking process?
When a CometD client is redirected to the second server by the load balancer, the second server does not know about this client.
The client will send a /meta/connect message with clientId=123, and the second server will reply with a 402::unknown_session and advice: {reconnect: "handshake"}.
When receiving the advice to re-handshake, the client will send a /meta/handshake message and will get a new clientId=456 from the second server.
Upon handshake, a well written CometD application will subscribe (even for dynamic subscriptions) to all needed channels, and eventually be restored to function as before, almost transparently.
Messages published to the client during the switch from one server to the other are completely lost: CometD does not implement any persistent feature.
However, persisting messages until the client acknowledged them is possible: CometD offers a number of listeners that are invoked by the CometD implementation, and through these listeners an application can persist messages (or other information) into their own choice of persistent (and possibly distributed) store: Redis, RDBMS, etc.
CometD handles reconnection transparently for you - it just takes a few messages between client and the new server.
You also want to read about CometD's in-memory clustering features.
I want to have multiple XMPP servers listening on upstream GCM messages for load balancing and fault tolerance. If I connect two servers to the same sender ID, would google automatically split the messages between them?
It's stated in Implementing an XMPP Connection Server that, periodically, CCS needs to close down a connection to perform load balancing to control messages.
Before it closes the connection, CCS sends a CONNECTION_DRAINING message to indicate that the connection is being drained and will be closed soon. "Draining" refers to shutting off the flow of messages coming into a connection, but allowing whatever is already in the pipeline to continue. When you receive a CONNECTION_DRAINING message, you should immediately begin sending messages to another CCS connection, opening a new connection if necessary. You should, however, keep the original connection open and continue receiving messages that may come over the connection (and ACKing them)—CCS handles initiating a connection close when it is ready.
I might be wrong but what I understand is that splitting of messages is not done since there's only one active connection. Sending of messages to another server starts as soon as CCS sends message that connection will be closed.
On this previous question: Tell when wcf client lost connection One of the commenters states:
Your service should not care whether a network cable was disconnected.
One feature of TCP is that unless someone is actively sending data, it
can tolerate momentary interruptions in network connectivity.
This is even more true in WCF, where there are layers of extra
framework to help protect you against network unreliability.
I'm having an issue where this is not working correctly. I have WCF client that makes a connection to the server using a DuplexChannelFactory. The connection stays open for 3 minutes. I disconnect the client from the internet and reconnect. The client regains internet connection, however any calls made from the server to that client fail. Once the client reconnects it begins working again.
When I pull the plug on the internet, the client throws several exceptions but the channel is still listed as being in an open state. Once the connection is regained and I made a request from the server to the client, I get errors such as: The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it has been Aborted.
Obviously if the request comes in when the client is offline it won't work, but I'm trying to get it so this channel will recover once the internet comes back without having to set up a new connection.
Should this be working as-is, based on the comment I listed above? Or is there something I need to change to make that actually work?
The issue here is that the channel you're trying to use is in a faulted state, and cannot be used any longer (as the error message indicates).
Your client needs to trap (catch) that exception, and then abort the current channel and create a new one. WCF will not do that for you automatically, you have to code for it yourself.
You could also check the CommunicationState of the channel to see if it is faulted, and recover that way.
A final option would be to use the OnFaulted event handler, and when the channel is faulted, abort the channel and create a new one.