UDP Discovery Tutorial – Part 1

I recently had a reason to look into this so I thought I’d post a short basic example of how to use UDP to implement client/server discovery over a local network in C#.  As this is a basic example, I am not going to cover security or negotiation minutia. At least not in these short tutorials. As a note to the reader, all error handling has been omitted for the sake of clarity.

Find the Broadcast IP of your Network

A special “Broadcast Address” must be used when using UDP for the purpose of sending a datagram to all machines connected to a given network.  For example, the typical home network host/gateway of 192.168.0.1 has a broadcast address of 192.168.0.255.  If your network differs from this you can use an IPv4 broadcast address calculator like the one found here http://jodies.de/ipcalc.  We don’t want to have to figure out the broadcast IP by hand every time so we’d like to calculate it programatically.

The below example code shows one possible way of how to calculate the broadcast address for your local network adapter.  Depending on your needs, there is also a special definition for the 255.255.255.255 broadcast address which is the broadcast IP for the 0.0.0.0 network.  This special broadcast address is more limited by definition in that packets sent to it are not forwarded to the routers connecting the local network to other networks.

The below code is a fully encapsulated method to return the broadcast address of the machine that it is running on. The return is a object of the IPAddress type.

        public IPAddress calculateUdpBroadcastAddress()
        {
            //Get the local IP address of the network adapter
            IPHostEntry host;
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily.ToString() == "InterNetwork")
                {
                    localIP = ip;
                }
            }

            //Get the SubnetMask of the Local Network Adapter
            foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces())
            {
                foreach (UnicastIPAddressInformation unicastIPAddressInformation in adapter.GetIPProperties().UnicastAddresses)
                {
                    if (unicastIPAddressInformation.Address.AddressFamily == AddressFamily.InterNetwork)
                    {
                        if (localIP.Equals(unicastIPAddressInformation.Address))
                        {
                            localSubnetMask = unicastIPAddressInformation.IPv4Mask;
                        }
                    }
                }
            }

            //Get the SubnetMask bytes before finding the complement
            IPAddress complimentIP = new IPAddress(localSubnetMask.Address);
            byte[] addressBytes = complimentIP.GetAddressBytes();
            byte[] complimentBytes = new byte[4];

            //Get the compliment of the SubnetMask
            for (int i = 0; i < addressBytes.Length; i++)
            {
                complimentBytes[i] = (byte)~addressBytes[i];
            }

            //bitwise OR the compliment of the Subnet Mask and the host IP
            byte[] localBytes = localIP.GetAddressBytes();
            byte[] broadcastBytes = new byte[4];
            for (int i = 0; i < localBytes.Length; i++)
            {
                broadcastBytes[i] = (byte)(complimentBytes[i] | localBytes[i]);
            }

            //Return the calculated broadcast address
            return new IPAddress(broadcastBytes);
        }

With the above code we can find the broadcast IP that we need to broadcast on to find our clients or server.

Select a Listening/Broadcasting Port

Any free port on both your client and server is acceptable for this purpose. MSDN uses port 11000 for their udp example. Personally I like utilizing ports in the 10k to 11k range for me projects as there is a fair amount of free ports in that range.

The port you’ve selected will be used in the following code example, for this example I am using port 11000.

Code to Implement the Listener

            //Update the UI and listen for a datagram until we get the right one
            bool done = false;
            while (!done)
            {
                byte[] bytes = udpListen();  //Blocking method call until a datagram is received

                //Validate the message
                string udpMessage = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
                string[] udpDatagramParts = udpMessage.Split(' ');
                if (!udpDatagramParts[0].Equals("UDPBroadcasterIP:"))
                {
                    //The UDP message we received is not the right one
                    listView.Items.Add("The received datagram was incorrect ... continue listening");
                }
                else
                {
                    //The udp message is the right one
                    listView.Items.Add("Received a correct datagram ... attempting a TCP connection ... ");
                    //Save the IP for the TCP connection
                    connectionIP = udpDatagramParts[1];
                    done = true;
                }
            }

Note: The third parameter to Console.WriteLine, “Encoding.ASCII…” represents the string value sent over UDP in the datagram packet. This contains the desired negotiation information for a discovery situation, such as the IP address of the client or server you wish to connect to.

The above code is performing a blocking listen operation until a UDP datagram has been received. The UdpListen() method can be seen in its entirety in the available visual studio projects listed at the bottom of this article.

Code to Implement the Broadcaster

            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            //The sendBuf contains the message we are sending to the UDPListener, so here is where the application specific validation
            // information and the TCP connection information will be provided to the listener
            byte[] sendbuf = Encoding.ASCII.GetBytes("UDPBroadcasterIP: " + localIP.ToString());
            IPEndPoint ep = new IPEndPoint(broadcastAddress, udpPort);

            for (int i = 0; i < 100; i++)
            {
                s.SendTo(sendbuf, ep);
                Thread.Sleep(10);
            }

This is a very simple example. The broadcaster is rebroadcasting for a period of time to make sure the Listener receives it. In this example I send the datagram every 10 milliseconds for 1 second. Even after the UDP datagram is sent/received there will need to be some negotiation to ensure a more permanent connection is made between the client and server.

In Part 2 of this tutorial I will implement a TCP connection between the Broadcaster and the Listener.  Once Part 2 is published I will also update the below code projects to show the TCP connection as well.

A full implementation of this tutorial is available for download at the link below. This is still a simplified version of what you will likely need for your project but should be more complete than the above code snippets.

UDPListener.zip

UDPBroadcaster.zip

 

2 thoughts on “UDP Discovery Tutorial – Part 1”

Leave a Reply to Aaron Cancel reply

Your email address will not be published. Required fields are marked *