I've experimented once on UDP (Unicast, Multicast and Broadcast) and undermined it always as I read a lot about its unreliability in data transmission. Today, I've read an article, UDP Delivers BUT I'm not sure whether it's suitable for this, my first experimental app with MVVM, type of application. On that, I'd two type of Clients: Ordinary which has the ability to submit, modify and delete an order and Special with an additional ability to send news to the Server. Server handles both Orders and News and eventually broadcasts (in a Parallel.ForEach) those to all connected Clients. I've used TCP in that.
Now, with UDP, I've 3 things: a Trade Server, Server, which receives only orders and broadcasts processed order, a News Server, Press, broadcasts only news and a Client, listens to two broadcasting Ports (Trade and News) and submits orders to the Trade Server. So far I've created the basic communication functionalities like this:
When I click Listen on Trade Server, it does the following:
void start(object o)
{
broadcastPoint = new IPEndPoint(IPAddress.Parse(Constants.TRADE_NET), Constants.TRADE_PORT);
receivePoint = new IPEndPoint(IPAddress.Parse(Constants.ORDER_IP), Constants.ORDER_PORT);
broadcaster = new Socket(SocketType.Dgram, ProtocolType.Udp) { EnableBroadcast = true };
receiver = new Socket(SocketType.Dgram, ProtocolType.Udp);
receiver.Bind(receivePoint);
receiveSource = new CancellationTokenSource();
Task.Run(receiveOrder, receiveSource.Token);
Task.Run(processOrder);
}
receiveOrder
function just puts the buffer in a ConcurrentQueue
and restarts receiving orders:
void receiveOrder()
{
var buffer = new byte[Constants.ORDER_SIZE];
while (!receiveSource.IsCancellationRequested)
{
receiver.Receive(buffer);
orderQueue.Enqueue(buffer.ToArray());
}
}
right now processOrder only dequeues and broadcasts:
void processOrder()
{
while (true)
{
if (orderQueue.Count > 0)
{
byte[] buffer;
while (!orderQueue.TryDequeue(out buffer)) { }
broadcaster.SendTo(buffer, broadcastPoint);
}
else Thread.Sleep(100);
}
}
BUT it actually will check for execution first and then broadcast one or more orders. Press is simple, it's initialized with:
newsPoint = new IPEndPoint(IPAddress.Parse(Constants.NEWS_NET), Constants.NEWS_PORT);
broadcaster = new Socket(SocketType.Dgram, ProtocolType.Udp) { EnableBroadcast = true };
and on button click it broadcasts each new and sleeps for 50ms:
void broadcast(object o)
{
foreach (var @new in News)
{
var buffer = Encoding.UTF8.GetBytes(@new);
broadcaster.SendTo(buffer, newsPoint);
Thread.Sleep(50);
}
...
}
Client's initialized with these:
tradePoint = new IPEndPoint(IPAddress.Any, Constants.TRADE_PORT);
newsPoint = new IPEndPoint(IPAddress.Any, Constants.NEWS_PORT);
orderPoint = new IPEndPoint(IPAddress.Parse(Constants.ORDER_IP), Constants.ORDER_PORT);
tradeClient = new Socket(SocketType.Dgram, ProtocolType.Udp);
newsClient = new Socket(SocketType.Dgram, ProtocolType.Udp);
orderClient = new Socket(SocketType.Dgram, ProtocolType.Udp);
tradeClient.Bind(tradePoint);
newsClient.Bind(newsPoint);
receiveSource = new CancellationTokenSource();
Task.Run(receiveOrder, receiveSource.Token);
Task.Run(receiveNews, receiveSource.Token);
Task.Run(processOrder, receiveSource.Token);
SubmitOrder = new Command(submitOrder, (o) => true);
Client's receiveOrder
and receiveNews
is similar to receiveOrder
of Trade Server:
void receiveOrder()
{
var buffer = new byte[Constants.ORDER_SIZE];
while (!receiveSource.IsCancellationRequested)
{
tradeClient.Receive(buffer);
orderQueue.Enqueue(buffer.ToArray());
}
}
processOrder
, right now, dequeues order from orderQueue and displays that on UI with an ObservableCollection and Client submits order in SubmitOrder function like this:
void submitOrder(object o)
{
orderClient.SendTo(Encoding.UTF8.GetBytes("Order " + no++), orderPoint);
}
ORDER_SIZE is 88 bytes and NEWS_SIZE is 1024 bytes.
all that left is to design the UI, do some computation and have another TCP Socket on both Trade Server and Client to send/receive queued/processedOrder when it first connects. BUT before that the relevant question is should UDP be used for this type of application?