Error handling during broadcasting message using WebSocketCollection object - c#

I'm currently using .Net 4.5 websocket package to support websocket service on windows 2012 server.
Using WebSocketCollection object I'm succesfully able to broadcast message to all the clients.
private static WebSocketCollection m_clients = new WebSocketCollection ();
m_clients.Broadcast(“Hello all”));
Here how to be sure all clients have received broadcasted messages? If some clients couldn't able to receive message how can I track those error messages? What king of error handling mechanism shall I need to use?
There is a onError virtual function. But I'm not sure how it will work during failure case of broadcasted message.
public virtual void OnError();

Could you not get the clients to "Acknowledge" the receipt of a packet, if a client does not Acknowledge the packet then chances are it wasn't received correctly.
If you are just wanting to keep the connection alive send a "Ping" message to the client before timeout. Likewise you could code the client to Ping the server at a scheduled time, if no Ping received then that could indicate that there is a problem?

Related

Why does my basic tcp chat application only work when connections are ended via ECONNRESET in nodejs?

I have a weird scenario and I'm not sure how to solve it.
I have a simple tcp chat server in nodejs and my clients are currently in native C#, and eventually will move to Unity. I have my own networking library which creates the TCP connection and handles messages etc, and works fine in some cases until it comes to disconnecting.
The server is running on an EC2 instance and I am loading two windows on my PC to test the multiple connections. When I close the window, I receive this error in the nodejs server console
Error: read ECONNRESET
at exports._errnoException (util.js:870:11)
at TCP.onread (net.js:544:26)
Which is fine, because this is the scenario where it works. I'm guessing this just means that the connection was abruptly closed (closing the window).
However problems arise when I instruct the socket to be shutdown.
I am porting my client to Unity and when closing the client, it does not produce this ECONNRESET error and the connection never closes abruptly (like I'd expect it to), so in this case I have to manually close the connection on the client which results in a different error.
Error: This socket has been ended by the other party
at Socket.writeAfterFIN [as write] (net.js:268:12)
at /opt/chat/chat.js:32:10
at Array.forEach (native)
at broadcast (/opt/chat/chat.js:31:10)
at Socket.<anonymous> (/opt/chat/chat.js:26:2)
at emitNone (events.js:72:20)
at Socket.emit (events.js:166:7)
at endReadableNT (_stream_readable.js:905:12)
at nextTickCallbackWith2Args (node.js:441:9)
at process._tickCallback (node.js:355:17)
When I receive this error on the server, the other connected clients can continue messaging the server, however they cannot receive messages from it.
My nodejs server was pulled from github here:
https://gist.github.com/creationix/707146
// Load the TCP Library
net = require('net');
// Keep track of the chat clients
var clients = [];
// Start a TCP Server
net.createServer(function (socket) {
// Identify this client
socket.name = socket.remoteAddress + ":" + socket.remotePort
// Put this new client in the list
clients.push(socket);
// Send a nice welcome message and announce
socket.write("Welcome " + socket.name + "\n");
broadcast(socket.name + " joined the chat\n", socket);
// Handle incoming messages from clients.
socket.on('data', function (data) {
broadcast(socket.name + "> " + data, socket);
});
// Remove the client from the list when it leaves
socket.on('end', function () {
clients.splice(clients.indexOf(socket), 1);
broadcast(socket.name + " left the chat.\n");
});
// Send a message to all clients
function broadcast(message, sender) {
clients.forEach(function (client) {
// Don't want to send it to sender
if (client === sender) return;
client.write(message);
});
// Log it to the server output too
process.stdout.write(message)
}
}).listen(5000);
// Put a friendly message on the terminal of the server.
console.log("Chat server running at port 5000\n");
Scenario
Let's assume we have CLIENT A on the left and CLIENT B on the right
On initial connection, they can both chat fine.
CLIENT B wishes to disconnect, and the code forces the disconnect by terminating the socket. The nodejs server receives the error "This socket has been ended by the other party" and broadcasts that this player has disconnected to CLIENT A
CLIENT A wishes to continue communicating, regardless that no one is connected. CLIENT A continues typing and sending messages, however the messages are not being received once CLIENT B has disconnected. However, the messages are indeed being sent to the server.
CLIENT A is NOT receiving his own messages.
CLIENT B wishes to reconnect to continue chatting and does so.
CLIENT A sends message 'hello'
CLIENT B sends message 'hello'
CLIENT B is seeing both messages, and experiencing a normal chat, however CLIENT A is not seeing any of the messages and is stuck on a blocking call trying to read data.
This is ONLY when I force the socket closed, and it works perfectly fine when I receive the ECONNRESET error. How can I replicate this error, or fix my issue?
EDIT
I have managed to reproduce the ECONNRESET error and now it works, but it still doesn't explain why it doesn't work with other errors.
The methods Close and GetStream().Close in C# TcpClient are not sufficient it seems to close a connection properly. Instead I had to access the socket directly and close that.
Closing the socket directly works in a native C# application but not in Unity.
To replicate this error in Unity I have to use
Shutdown(SocketShutdown.Receive);

Connection specific AppendShutdownHandler

I'm using NetworkComms.Net and I'm currently trying to create a sort of forwarder which listens on a port (calling it GATEWAY), which receive a certain packet (from CLIENT) which will tell him where to redirect next pacekts coming from the same client.
Example:
CLIENT tell GATEWAY that he needs to get to SERVER:serverport
GATEWAY creates a connection to SERVER:serverport
CLIENT sends packets to GATEWAY which sends them to SERVER
SERVER sends back a response, which goes through the GATEWAY to the CLIENT.
I had it working with Net.Sockets and I’m now changing to NetworkComms.
The problem I’m facing is that when a connection from Gateway (client) to Server (listening server) is closed, the Gateway trigger the global callbacks for connection/disconnection:
NetworkComms.AppendGlobalConnectionCloseHandler(ClientDisconnected);
NetworkComms.AppendGlobalConnectionEstablishHandler(ClientConnected);
Those callbacks are supposed to be only called when a client connect or disconnect on the Gateway
This is the code i’m currently using to start the listener.
NetworkComms.DefaultSendReceiveOptions = new SendReceiveOptions<ProtobufSerializer, , LZMACompressor>();
NetworkComms.DefaultSendReceiveOptions.IncludePacketConstructionTime = NetworkComms.DefaultSendReceiveOptions.ReceiveHandlePriority = QueueItemPriority.AboveNormal;
NetworkComms.AppendGlobalConnectionCloseHandler(SessionClosed);
NetworkComms.AppendGlobalConnectionEstablishHandler(NewSessionConnected);
NetworkComms.AppendGlobalIncomingPacketHandler<string>("ECHO", SocketCommands.HandleIncomingECHOPacket);
Connection.StartListening(ConnectionType.TCP, new IPEndPoint(IPAddress.Any, 10000));
I suppose this is like a “global” way of starting It?
How do I start one then add those Connected/Disconnected handlers to just the listener?
Thanks

Does TcpClient write method guarantees the data are delivered to server?

I have a separate thread on both client and server that are reading/writing data to/from a socket.
I am using synchronous TcpClient im (as suggested in documention):
https://msdn.microsoft.com/cs-cz/library/system.net.sockets.tcpclient%28v=vs.110%29.aspx
When connection is closed .Read()/.Write() throws an exception. Does it mean that when .Write() method does not throw the data were delivered correctly to the other party or do I need to implement custom ACK logic?
I read documentation for both Socket and TcpClient class and none of them describe this case.
All that a returning send() call means (or any wrapper you use, like Socket or TcpClient) on a streaming, blocking internet socket is that the bytes are placed in the sending machine's buffer.
MSDN Socket.Send():
A successful completion of the Send method means that the underlying system has had room to buffer your data for a network send.
And:
The successful completion of a send does not indicate that the data was successfully delivered.
For .NET, the underlying implementation is WinSock2, documentation: send():
The successful completion of a send function does not indicate that the data was successfully delivered and received to the recipient. This function only indicates the data was successfully sent.
A call to send() returning does not mean the data was successfully delivered to the other side and read by the consuming application.
When data is not acknowledged in time, or when the other party sends a RST, the Socket (or whichever wrapper) will become in a faulted state, making the next send() or recv() fail.
So in order to answer your question:
Does it mean that when .Write() method does not throw the data were delivered
correctly to the other party or do I need to implement custom ACK logic?
No, it doesn't, and yes, you should - if it's important to your application that it knows another party has read that particular message.
This would for example be the case if a server-sent message indicates a state change of some sort on the client, which the client must apply to remain in sync. If the client doesn't acknowledge that message, the server cannot know for certain that the client has an up-to-date state.
In that case you could alter your protocol so that certain messages have a required response which the receiver must return. Do note that implementing an application protocol is surprisingly easy to do wrong. If you're inclined, you could implement having various protocol-dictated message flows using a state machine,
for both the server and the client.
Of course there are other solutions to that problem, such as giving each state a unique identifier, which is verified with the server before attempting any operation involving that state, triggering the retry of the earlier failed synchronization.
See also How to check the capacity of a TCP send buffer to ensure data delivery, Finding out if a message over tcp was delivered, C socket: does send wait for recv to end?
#CodeCaster's answer is correct and highlights the .NET documentation specifying the behavior of .Write(). Here is some complete test code to prove that he is right and the other answers saying things like "TCP guarantees message delivery" are unambiguously wrong:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace TestEvents
{
class Program
{
static void Main(string[] args)
{
// Server: Start listening for incoming connections
const int PORT = 4411;
var listener = new TcpListener(IPAddress.Any, PORT);
listener.Start();
// Client: Connect to listener
var client = new TcpClient();
client.Connect(IPAddress.Loopback, PORT);
// Server: Accept incoming connection from client
TcpClient server = listener.AcceptTcpClient();
// Server: Send a message back to client to prove we're connected
const string msg = "We are now connected";
NetworkStream serverStream = server.GetStream();
serverStream.Write(ASCIIEncoding.ASCII.GetBytes(msg), 0, msg.Length);
// Client: Receive message from server to prove we're connected
var buffer = new byte[1024];
NetworkStream clientStream = client.GetStream();
int n = clientStream.Read(buffer, 0, buffer.Length);
Console.WriteLine("Received message from server: " + ASCIIEncoding.ASCII.GetString(buffer, 0, n));
// Client: Close connection and wait a little to make sure we won't ACK any more of server's messages
Console.WriteLine("Client is closing connection");
clientStream.Dispose();
client.Close();
Thread.Sleep(5000);
Console.WriteLine("Client has closed his end of the connection");
// Server: Send a message to client that client could not possibly receive
serverStream.Write(ASCIIEncoding.ASCII.GetBytes(msg), 0, msg.Length);
Console.WriteLine(".Write has completed on the server side even though the client will never receive the message. server.Client.Connected=" + server.Client.Connected);
// Let the user see the results
Console.ReadKey();
}
}
}
The thing to note is that execution proceeds normally all the way through the program and serverStream has no indication that the second .Write was not successful. This is despite the fact there is no way that second message can ever be delivered to its recipient. For a more detailed look at what's going on, you can replace IPAddress.Loopback with a longer route to your computer (like, have your router route port 4411 to your development computer and use the externally-visible IP address of your modem) and monitor that port in Wireshark. Here's what the output looks like:
Port 51380 is a randomly-chosen port representing the client TcpClient in the code above. There are double packets because this setup uses NAT on my router. So, the first SYN packet is my computer -> my external IP. The second SYN packet is my router -> my computer. The first PSH packet is the first serverStream.Write. The second PSH packet is the second serverStream.Write.
One might claim that the client does ACK at the TCP level with the RST packet, but 1) this is irrelevant to the use of TcpClient since that would mean TcpClient is ACKing with a closed connection and 2) consider what happens when the connection is completely disabled in the next paragraph.
If I comment out the lines that dispose the stream and close the client, and instead disconnect from my wireless network during the Thread.Sleep, the console prints the same output and I get this from Wireshark:
Basically, .Write returns without Exception even though no PSH packet was even dispatched, let alone had received an ACK.
If I repeat the process above but disable my wireless card instead of just disconnecting, THEN the second .Write throws an Exception.
Bottom line, #CodeCaster's answer is unambiguously correct on all levels and more than one of the other answers here are incorrect.
TcpClient uses TCP protocol which itself guarantees data delivery. If the data is not delivered, you will get an exception. If no exception is thrown - the data has been delivered.
Please see the description of the TCP protocol here: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
Every time the data is sent, the sending computer waits for the acknowledgement packet to arrive, and if it has not arrived, it will re-try the send until it is either successful, timed out, or permanent network failure has been detected (for example, cable disconnect). In the latter two cases an exception will be thrown
Therefore, TCP offeres guaranteed data delivery in the sense that you always know whether the destination received your data or not
So, to answer your question, you do NOT need to implement custom ACK logic when using TcpClient, as it will be redundant
Guarantee is never possible. What you can know is that data has left your computer for delivery to other side in the order of data was sent.
If you want a very reliable system, you should implement acknowledgement logic by yourself based on your needs.
I agree with Denis.
From the documentation (and my experience): this method will block until all bytes were written or throw an exception on error (such as disconnect). If the method returns you are guaranteed that the bytes were delivered and read by the other side on the TCP level.
Vojtech - I think you missed the documentation since you need to look at the Stream you're using.
See: MSDN NetworkStream.Write method, in the remarks section:
The Write method blocks until the requested number of bytes is sent or a SocketException is thrown.
Notes
Assuring that the message was actually read properly by the listening application is another issue and the framework cannot guarantee this.
In async methods (such as BeginWrite or WriteAsync) it's a different ballgame since the method returns immediately and the mechanism to assure completion is different (EndWrite or task completion paired with a code).

WCF Net.TCP: Most efficient way to broadcast messages to a lot of clients

I have a WCF service hosted with Net.TCP binding to which a lot of clients (> 100) may connect and receive various broadcast messages. The same message is sent to all clients and the current way I'm currently doing it is to have dedicated thread which waits on a BlockingCollection for new messages and as soon as new message arrives it iterates over the list of client callback connections and calls a method which receives the message as an argument.
So my code currently looks like this:
var msg = ... get message from queue ...
foreach(var client in clients)
client.SendMessage(message)
This design has following problems:
Clients can not receive new message until I'm finished sending a message to all clients
I would like to detect slow clients and possibly disconnect them
The message is being serialized as many times as I have clients (I could change it so that I serialize the message before sending it but I would need to change the signatore of SendMessage to SendMessage(byte[] content) and this is not something I would like to do)
Does anybody has experience with such problems? Any tips/tricks/hints?
It seems you have to use multicasts instead of dedicated communication. So each new client will need to join the cast channel (see IGMP for details) and then your server will fire-and-forget once per message you need to publish.

Handler for pong message in WampSharp client

I have a WampSharp client which successfully pings my Wamp WS server created in python every 1 minute.
I am sending a pong message from the server to the client on the receipt of the ping.
I would like to know whether there is any handler which will handle the receipt of the pong message in WampSharp client so that I could perform certain tasks at client side?
And if there isn't any separate handler for the pong message then is there any handler to handle the data received from the server like in traditional WebSocket client which is as follows?
webSocket.MessageReceived += new EventHandler<MessageReceivedEventArgs>(webSocket_MessageReceived);
Thanks in advance.
I just uploaded to NuGet a version of WampSharp that allows you to specify the underlying WebSocket you want to use for a WampChannel.
Usage:
DefaultWampChannelFactory factory = new DefaultWampChannelFactory();
WebSocket socket = new WebSocket("ws://localhost:9090/ws", "wamp");
IWampChannel<JToken> channel = factory.CreateChannel(socket);
socket.DataReceived += OnDataReceived;
await channel.OpenAsync();
As you see, you can also subscribe to underlying WebSocket's events. I don't really like this, since this removes WampSharp's WebSocket encapsulation, but if you know what you're doing, I won't stop you.

Categories