Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Send and receive messages in a LAN with broadcasting

5.00/5 (17 votes)
6 Mar 2012MIT9 min read 97.1K   11.7K  
Lightweight .Net library for UDP LAN broadcasting.

Library (v2)

Examples

Contents 

  • Introduction  
  • What exactly is the Broadcast 
  • Where is my stuff  
  • Quick start 
  • About the examples attached   
  • The magic inside the v2 library  
  • The magic inside the v1 library (previous version) 
  • Conclusion  

Introduction

UDP allows us to broadcast messages across a Tcp/Ip LAN. Some applications could be:

  • LAN tests.
  • P2P logic.
  • LAN chat.
  • LAN indie games.
  • Server discovery instructions. A client asks for a server. Then, a server answers with the IP and the port to which the client can connect. 
  • etc.

This article proposes a way to organize the selected core objects and threads, in order to build up an encapsulated class that exposes clean methods and properties. It also solves the main difficulties that developers find when trying to take advantage of the UDP broadcasting:

  • Sending and receiving simultaneously causes a "the port is in use" exception.
  • The receive method blocks the execution until something is received.
  • Broadcasted packets are public on LAN but privacy is needed.

Solutions for this difficulties along with some others can be found in this article:

  • feeding the Microsoft UdpClient object on the right parameters.
  • creating separate threads for the receiver and the listener.
  • setting a timeout to the receiver / using BeginReceive instead of Receive
  • encrypting the messages.
  • decoupling threads with thread safe accessed methods and properties. 

What exactly is the Broadcast

"Broadcast is the term used to describe communication where a piece of information is sent from one point to all other points. In network case there is just one sender, but the information is sent to all connected receivers. Broadcast is mostly used in local sub networks. In order to transmit broadcast packet, the destination MAC address is set to FF:FF:FF:FF:FF:FF and all such packets will be received by other NICs." (1)

As opposed to Multicast: "Multicast (point-to-multipoint) is a communication pattern in which a source host sends a message to a group of destination hosts. The notion of group is essential to the concept of multicasting. By de?nition a multicast message is sent from a source to a group of destination hosts." (1)

There are two types of Broadcast:

  • Limited Broadcast - Sent to all NICs on the some network segment as the source NIC. It is represented with the 255.255.255.255 TCP/IP address. This broadcast is not forwarded by routers so will only appear on one network segment.
  • Direct broadcast - Sent to all hosts on a network. Routers may be configured to forward directed broadcasts on large networks. For network 192.168.0.0, the broadcast is 192.168.255.255. 

In this article we will build a library to perform Limited Broadcasts. 

Where is my stuff

If you came here looking for a quick way to broadcast messages, you may want to download the v2 dll binaries, add it to your project and start broadcasting. A simple example code is shown below in the Quick Start section along with some instructions. If you want to see some more complex examples you may want to download The Chat or the Sink The Boat Game and see what happens.

If you came here to learn how to UDP broadcast or to play with it, I suggest downloading the v1 source code. The equivalent Quick Start example is inside the file. The Magic Inside The v1 Library section will introduce you to the v1 library. You will soon notice that the library has lot of room for improvement and that some udp parameter combinations and optimization are allowed. You may want to test it in an IPv6 environment, direct broadcast, etc. You will have fun with this one. If you write something you are proud of and is share-able, my curiosity would be happy to see it. 

Quick Start   

Using the library  

The use of the library is pretty straightforward.

  1. Add the library: Download the .dll and place it in your project. Add a reference to that library.
  2. Declaration and initialization
  3. Broadcasting messages
  4. Receiving broadcasted messages
  5. Disposing 

Tiny example 

One of the smallest programs we could write to show how this library works is a console chat. The program will be able to receive any messages sent to Lan, decrypt it and show it on the console. It will also be able to send a user message to Lan. The program uses a thread to show the messages received as soon as they are received. The library is thread safe. Here is the code of this tiny example:

C#
using System;
using System.Threading;
using Orekaria.Lib.P2P;

namespace Orekaria.Test.P2P.ConUI
{
    internal class Program : IDisposable
    {
        private readonly BroadcastHelper _broadcast;
        private readonly Thread _th;

        private Program() {
            _broadcast = new BroadcastHelper(8010, "K_*?gR@Ej");
            _th = new Thread(DequeueMessages);
            _th.Start();
        }

        #region IDisposable Members

        public void Dispose() {
            _th.Abort();
        }

        #endregion

        private void Run() {
            var isExit = false;
            do {
                var s = Console.ReadLine();
                if (s != null && s.ToLower() == "exit")
                    isExit = true;
                else
                    _broadcast.Send(string.Format("{0}: {1}", Environment.UserName, s));
            } while (!isExit);
        }

        private void DequeueMessages() {
            while (_th.IsAlive) {
                Thread.Sleep(100);
                while (_broadcast.Received.Count > 0)
                    Console.WriteLine(string.Format("{0}", _broadcast.Received.Dequeue()));
            }
        }

        private static void Main() {
            var p = new Program();
            p.Run();
            p.Dispose();
        }
    }
}
Key lines are both in bold and in italics. The library is declared in the first lines and a new thread is started to show the messages as soon as they are received. Then the process keeps reading the user console until "exit" is typed. The send method is the one responsible for broadcasting the messages. You would like to test this example in a LAN to see how messages are received by everybody. 

The output when 2 users called DAM and ASIR are executing this code is this. The first line "ASIR: Hello DAM" being the remote computer, the line "Hello" being the local user writing a response and "DAM: Hello" being the local echo of the "Hello" response that has been broadcasted and then received back:

326868/p2pCon.png

About the examples attached 

The examples included use the library for specific goals. The first one is a Wpf LAN chat and the second one is a Forms LAN game called Sink the Boat. The chat is quite the same as the above console example but translated into very basic Wpf code. The LAN game is more complex because it shows how this library could be use to send packed messages or serialized content. These are some decrypted messages that are broadcasted in this LAN game:

326868/p2pBoatMsg.png

When one of these messages is received, the code below depacks the information within the message. It is not important how they are packed. You should use your own package algorithm. It is shown here for demonstration purposes:

VB.NET
Private Sub ProcesaPaquete(messageReceived As String)
    Dim parts = messageReceived.Split(" ")
    Dim hostEmitter = CatalogHost(parts(0))
    If parts.Length = 2 Then
        hostEmitter.PingReceived(Convert.ToInt32(parts(1)))
        Return
    End If
    Dim target = parts(1)
    Dim hostTarget = LogHost(target)
    Dim mb = New processParts(messageReceived, Convert.ToInt32(parts(2)), parts(3))
    hostTarget.MessageReceived(mb)
End Sub 

In the code above, the received message is unpacked and the information is classified in one of three categories: ping, shoot or impact. Each of these messages contains different information which is processed afterwards.

The magic inside the v2 library

The v2 library consists of two classes. One is called BroadcastHelper and the other one is called UdpHelper. The BroadcastHelper is the only class being exposed. The constructor must be called with the port and an optional encrypt pass phrase. It exposes a method called Send that allows you to broadcast a message to the LAN and a property called Received that maintains a queue of all the messages that have been broadcasted by any host in the LAN. 

Inside the BroadcastHelper, a listener and a talker manage the messages. Both of them work with a UdpClient object and with a IPEndPoint address. The key parameters are the port and IPAddress.Broadcast. Remember that we are Limited Broadcast-ing so the address should be 255.255.255.255. The listener is instantiated in this way:

C#
var udp = new UdpClient(_port);
var remoteEP = new IPEndPoint(IPAddress.Broadcast, 0);
_listener = new UdpHelper(udp, remoteEP); 

 and the talker in this way: 

C#
var udp = new UdpClient()
var remoteEP = new IPEndPoint(IPAddress.Broadcast, _port);
_talker = new UdpHelper(udp, remoteEP)

Compared to the v1 version, the timeout is no longer necessary because we will use a callback to receive possible broadcasted messages and this callback don´t block the execution flow. Before continuing you may want to check the debug prints (results window in VisualStudio) to check how the listener and the talker are lazy loaded and the ports that they are using.

Leaving the BroadcastHelper and inside the UdpHelper, messages are sent right away:

C#
{ ...
    _udpClient.Send(packetBytes, packetBytes.Length, _remoteEP);
}

but the receiver collects the new messages through a callback not to block the execution flow. When a message is received another callback is queued:

C#
{ ...
    _udpClient.BeginReceive(ReceiveCallback, null)
}

private void ReceiveCallback(IAsyncResult ar) {
    var receiveBytes = _udpClient.EndReceive(ar, ref _remoteEP);
    _received.Enqueue(ChosenEncoder.GetString(receiveBytes));
    _udpClient.BeginReceive(ReceiveCallback, null);
}

Finally, the destructor is instructed to automatically close and free the resources. 

C#
~UdpHelper() {
    _udpClient.Close();
}

The magic inside the v1 library  

Library (v1)

I do really like this v1 library. I know... it is probably not the optimal way to go, but I do like its logic simplicity. Art and beauty also exist in our code lines, don´t it?. 

The library consists of two classes. One is called P2PHelper and the other one is called UDPHelper. As a side note, this is a project much bigger than the one presented here and so is the name P2PHelper. This class, P2PHelper, is the only public exposed class. Three methods and a property are visible: the constructor, Dispose, Send and Received.

When P2PHelper is instantiated, two threads are created, each one containing an instance of the UDPHelper class. The UDPHelper class encapsulates and simplifies the System.Net.Sockets.UdpClient and the System.Text.Encoding. You may like to change your preferred encoding here.

Listening and talking to the LAN

One of the threads is used for listening and the other one for talking. I must point here as I did in the code, that both threads could be use for listening and speaking having a total of 2x2.

The listening thread (called server in the code), needs some specific parameters to enter the broadcast listener mode. Keys are the port, the IPAddress.Broadcast and the timeout to allow the thread to exit the listening state:

C#
var udpServer = new UdpClient(_port) {Client = {ReceiveTimeout = TimeOut}};
var serverEP = new IPEndPoint(IPAddress.Broadcast, 0);
var server = new UDPHelper(udpServer, serverEP);

The talking thread (called client in the code), although it uses the same UDPHelper class, needs other specific parameters to enter the broadcast talking mode. Keys are the IPAddress.Broadcast and the port we are talking through:

C#
var udpClient = new UdpClient();
var clientEP = new IPEndPoint(IPAddress.Broadcast, _port);
var client = new UDPHelper(udpClient, clientEP); 

If you are interested in tweaking and improving this code you should have enough room tweaking in this class, in particular the parameters sent to the UDPHelper class mentioned above. You will see how some changes do still work and some other fail.

After this two threads are created, the P2PHelper keeps listening and enqueueing the messages received. If encryption is enabled, the messages are decrypted:

C#
while (!_disposing) {
    var receive = server.Receive();
    if (receive != Resources.TimeOut)
        _received.Enqueue(_encrypt ? EncryptHelper.DecryptString(receive, _passPhrase) : receive);
    Thread.Sleep(1);
}  

and talking. If encryption is enabled, messages are encrypted:

C#
while (!_disposing) {
    while (_toSend.Count > 0) {
        var send = _toSend.Dequeue();
        client.Send(_encrypt ? EncryptHelper.EncryptString(send, _passPhrase) : send);
    }
    Thread.Sleep(10);
}  
Disposing

Disposing the object is required to free the resources. You may want to improve this code to fit your needs or even to work without this explicit disposing.

C#
public void Dispose()
{
    _disposing = true;
    _thClient.Join();
    _thServer.Join();
}

Conclusion

This article gives you a better understanding of how we can build code to be able to broadcast and receive messages in a LAN. Hope to get your feedback and suggestions.

References 

(1) Broadcasting and Multicasting in IP Networks 

History

5-Mar-2012: My english teacher helped me to fix some spelling and grammar errors.

6-Mar-2012: Added the v2 library.

License

This article, along with any associated source code and files, is licensed under The MIT License