Jarloo

Menu

C# UDP Multicasting Tutorial

Learn how to use a UDP Multicast in c# to quickly send data from one machine to a next. This method is commonly refered to as a UDP rendezvous.(yes probably why Tibco’s product that does this is called rendezvous)

This tutorial will consist of two programs:

  • Server (Sender) – a console app that is responsible for sending messages
  • Client (Listener) – a console app that is responsible for recieving messages

The reason they are both console apps is to keep things simple.

UDP Multicasting 101

Before we jump into the code there are a few things that you need to know.

Technically multicasting addresses must be between 224.0.0.0 to 239.255.255.255, but 224.0.0.0 to 224.0.0.255 is reserved for routing info so you should really only use 224.0.1.0 to 239.255.255.255.

For the port number you can choose anything you like but it’s best do investigate the port you choose a bit so you don’t conflict with something already using that port. A good place to look is wikipedia

UDP Multicasting C# Server (Sender)

The server must make a connection to our multicast address and then join our multicast group. By joining the group we can add content to it, which gets delivered to anyone else in the group.

IPAddress multicastaddress = IPAddress.Parse("239.0.0.222");
udpclient.JoinMulticastGroup(multicastaddress);
IPEndPoint remoteep = new IPEndPoint(multicastaddress, 2222);

Really that is it. The rest is just to encode the message and send it like so:

Byte[] buffer = null;
for (int i = 0; i <= 8000; i++)
{
	buffer = Encoding.Unicode.GetBytes(i.ToString());
	udpclient.Send(buffer, buffer.Length, remoteep);
}
&#91;/csharp&#93;

Now because this is a Console app we can add a new messages in there to see whats going on. The complete class looks like this:

&#91;csharp&#93;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Jarloo.Sender
{
    internal class Program
    {
        private static void Main(string&#91;&#93; args)
        {
            UdpClient udpclient = new UdpClient();

            IPAddress multicastaddress = IPAddress.Parse("239.0.0.222");
            udpclient.JoinMulticastGroup(multicastaddress);
            IPEndPoint remoteep = new IPEndPoint(multicastaddress, 2222);

            Byte&#91;&#93; buffer = null;

            Console.WriteLine("Press ENTER to start sending messages");
            Console.ReadLine();

            for (int i = 0; i <= 8000; i++)
            {
                buffer = Encoding.Unicode.GetBytes(i.ToString());
                udpclient.Send(buffer, buffer.Length, remoteep);
                Console.WriteLine("Sent " + i);
            }

            Console.WriteLine("All Done! Press ENTER to quit.");
            Console.ReadLine();
        }
    }
}
&#91;/csharp&#93;

<h2>UDP Multicasting C# Client (Listener)</h2>
Like the server the client must also connect to the multicast group


UdpClient client = new UdpClient();

IPEndPoint localEp = new IPEndPoint(IPAddress.Any, 2222);
client.Client.Bind(localEp);

IPAddress multicastaddress = IPAddress.Parse("239.0.0.222");
client.JoinMulticastGroup(multicastaddress);

Notice the code looks very similiar to the sender we created except that we bind to an endpoint. This is necessary as we will be listening for incoming data.

So now that were connected we just need to listen for messages and do something with them.

while (true)
{
	Byte[] data = client.Receive(ref remote);
	string strData = Encoding.Unicode.GetString(data);
	Console.WriteLine(strData);
}

Yes that is an infinate loop. (this is just for demonstration purposes remember?) To close this client down you will have to kill it. Yes there are easier ways including sending a quit message from the server etc.. etc.., but I didn’t want to add a bunch of code that would confuse things here.
Also important to note is that the client.Receive call is blocking. This means that code execution will halt on that line until a message is received. So if you do something similiar in your own programs you would either want this on a different thread or you would want to use the async methods instead. (Async methods are best because if you multi-thread it, to stop the client you will need to interrupt the thread which will throw an exception.)

One issue you’ll discover is that you can only have a single listener working on a machine at a time. This is because the port is set for exclusive use. So if you want multiple Listeners on a single machine you will need to change this by doing this:

client.ExclusiveAddressUse = false;
IPEndPoint localEp = new IPEndPoint(IPAddress.Any, 2222);

client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
client.ExclusiveAddressUse = false;

This would go right under the creation of the UdpClient.

The complete code the Listener looks like this:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Jarloo.Listener
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            UdpClient client = new UdpClient();

            client.ExclusiveAddressUse = false;
            IPEndPoint localEp = new IPEndPoint(IPAddress.Any, 2222);

            client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            client.ExclusiveAddressUse = false;

            client.Client.Bind(localEp);

            IPAddress multicastaddress = IPAddress.Parse("239.0.0.222");
            client.JoinMulticastGroup(multicastaddress);

            Console.WriteLine("Listening this will never quit so you will need to ctrl-c it");

            while (true)
            {
                Byte[] data = client.Receive(ref localEp);
                string strData = Encoding.Unicode.GetString(data);
                Console.WriteLine(strData);
            }
        }
    }
}

Summary

UDP Multicasting is a great way to send around data but there are a few things to look at to determine if this method is right for you.

Pros

  • Requires no dedicated server. Your client and server can be the same app, making this a very nice distributed solution with no single point of failure.
  • Fast. Very, very fast. Since there are no extra jumps to servers and translation etc the code executes very fast.

Cons

  • Messages are not guaranteed. They can be lost, so if your passing around something critical like banking transactions this wouldn’t be a good idea.

Common uses for this style of architecture are in places where data is updating very quickly and each message sent has a very short lifespan. You see this being used in trading shops quite a bit for sending prices. If a single price is lost, it’s not that big of a deal because another one will follow in seconds.

Alternatives

If your looking to route data to multiple machines the problem has been tackled before, and there are some great open source projects that work very well and can help. Two I would recommend are:

  • RabbitMQ – This is the easiest setup for a queuing system I have seen, and it once you get it up and running it just works without issue. I’ve been using this in a production scenario for over a year and am very happy with it. Used to use ActiveMQ but I’ve found this much better and more reliable.
    I have a RabbitMQ Tutorial if your interested.
  • ZeroMQ – This one I haven’t personally used yet, but it sounds very good and it created to be extremely low latency.

Hope you enjoyed this tutorial, if I get the time I’ll post an Async version of this.

Categories:   Code

Tags:  , ,

Comments

  • Posted: December 17, 2010 09:06

    F2K

    Great tutorial, but in the client code there is a mistake: Byte[] data = client.Receive(ref remote); should be: Byte[] data = client.Receive(ref localEp);
    • Posted: December 17, 2010 09:10

      kelias

      Thanks, I sometimes copy and paste too fast I think. I've updated the article.
  • Posted: December 25, 2010 05:35

    RAVIMR

    client.JoinMulticastGroup(multicastaddress); telling wrong multicastaddress while executing server
    • Posted: January 10, 2011 21:25

      kelias

      I would check your IP addresses again, it should work fine. Also ensure if your behind a router that it supports udp multicasting. Depending on your network you may need to specify the number of hops the message will travel.
  • Posted: January 24, 2012 14:59

    mike

    Great article, thanks! One Q - what else would need to be done if you wanted to use this from outside the LAN? I want to write an app I can use to sleep and wake PC's on my LAN from my windows phone or from an external PC.
    • Posted: January 24, 2012 15:16

      admin

      UDP is not the best spec to be using over the internet. Many routers filter the packets out, and the packets typically define a time to live (ttl), which defines a certain number of hops before they die. Some products such as Tibco's Rendezvous would use UDP locally but externally they would tunnel TCP instead, which might be the approach your looking for.
  • Posted: January 24, 2012 18:20

    Mike

    >externally they would tunnel TCP instead, which might be the approach your looking for. Thanks again, I will get it working first inside my LAN (thanks to your samples and a sample WP7 app I already have working) and then start looking into how I'd goa bout using TCP tunnelling. I'll have a service running on each PC containing the UDP listener, so would need to extend that to also listen for TCP messages I guess.
  • Posted: March 17, 2012 05:44

    shachar

    i did something similar , on the same machine i have 3 application that create a udpClient (192.168.1.101-103) that sends data and a udpClient that join's a multicast group and receiving data). my problem is that only 1 application receive data from whoever send data to the multicast group. when i close the application the got the data it falls to another , seems that only one ip can on the same machine can get the multicast message. is this true? or i'm doing something wrong? this is my c'tor: public UDPService(IPAddress ip, int port) { var ipEndPoint = new IPEndPoint(IPAddress.Any, port); RemoteEndPoint = new IPEndPoint(ip, port); // http://www.jarloo.com/c-udp-multicasting-tutorial/ //sender sender = new UdpClient(AddressFamily.InterNetwork); sender.Client.SendBufferSize = 10000000; sender.MulticastLoopback = true;//send to self. sender.ExclusiveAddressUse = false; //receiver receiver = new UdpClient(); receiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); receiver.ExclusiveAddressUse = false; receiver.Client.Bind(ipEndPoint); receiver.EnableBroadcast = true; } then i join to the multicast group public void JoinMulticastGroup(string ip) { // http://msdn.microsoft.com/en-us/library/2fxkak8t.aspx // The multicast address range is 224.0.0.0 to 239.255.255.255 IPAddress multiCastGroup = IPAddress.Parse(ip); receiver.JoinMulticastGroup(multiCastGroup, timeToLive); //timeToLive = hops. } and send data with: private void MulticastInternal(byte[] data) { sender.Client.SendTimeout = 2000; sender.Connect(RemoteEndPoint); sender.BeginSend(data, data.Length, multicast_Completed, sender); } void multicast_Completed(IAsyncResult result) { sender.EndSend(result); } thanks,
  • Posted: September 25, 2012 07:43

    Leonard Gambrell

    Can you do this over the interent? I've seen many UDP example but none work over the internet only locally. Thanks LPG
  • Posted: February 6, 2013 13:40

    Yury Schkatula

    Appending this tutorial, I'd like to say that in case of multiple network interfaces (including VPN) you can experience issues with multicast receiving. It's necessary to instruct OS to use each possible interface as a "multicast ear", something like that: NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface adapter in nics) { IPInterfaceProperties ip_properties = adapter.GetIPProperties(); if (!adapter.GetIPProperties().MulticastAddresses.Any()) continue; // most of VPN adapters will be skipped if (!adapter.SupportsMulticast) continue; // multicast is meaningless for this type of connection if (OperationalStatus.Up != adapter.OperationalStatus) continue; // this adapter is off or not connected IPv4InterfaceProperties p = adapter.GetIPProperties().GetIPv4Properties(); if (null == p) continue; // IPv4 is not configured on this adapter my_sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)IPAddress.HostToNetworkOrder(p.Index)); } Some notes are here, if you don't mind.
  • Posted: February 11, 2013 05:56

    J4N

    I've found a little bug: Byte[] data = client.Receive(ref localEp); The problem is that when you receive the message, the client change the IP (the multicast address) by the IP that has send the data(very usefull to know the sender BTW). This means that on the next iteration of your While(true) You will no longer try to read from broadcast but from the IP you got here. You should have something like this: IPEndPoint temporaryEP = new IPEndPoint(IPAddress.Any, 2222); Byte[] data = client.Receive(ref temporaryEP ); in your while loop. It resolved a lot problem for me.
  • Posted: February 17, 2013 22:23

    sakthi

    if we have a multiple receiver in a place.if any sound is occurred it will be captured bye the receiver.due to climate change there.may be slight change in time.each node it placed at variance distance.so time will be vary for each nodes.To solve this error,average time is calculated.so approximate time will be known,when the sound has occurred...To write a C# programming.....
  • Posted: April 18, 2013 00:14

    Peter Smith

    Hi, Just a comment on your Cons - actually reliable multicast (udp) is the main transport the banking industry uses for trading systems because of the reduced latency and bandwidth - typically you might only have to resend one in a million messages so they rarely (I've never seen it in production) get lost. Also, rolling your own udp framework is extremely hard and time consuming, something like RMF might be worth considering...
    • Posted: April 18, 2013 13:21

      Kelly Elias

      Good points. I've used UDP plenty in the past, as well as frameworks that do reliable UDP like Tibco Rendezvous. (I too work in the financial industry, at a commodity trading company.) This is the first time I've seen mesongo though. Looks interesting, I'll have to take it for a spin.
  • Posted: February 21, 2014 03:33

    Ramesh

    This article is very useful.
  • Posted: July 24, 2015 09:40

    Tim Tatum

    Thank you SO much. This is extremely helpful!
  • Posted: March 21, 2016 21:53

    michell

    Hi, great script, but how convert stream to binary (0 and 1)?