Creating an UDP Server with .NET Gadgeteer

Posted by Marco Minerva

Some time ago, we presented a simple TCP Server for .NET Gadgeteer, that has been used in many other projects. Today, we’ll see how to create another kind of server, based on UDP protocol.

Its behavior is similar to the one of our TCP Server, but it is simpler because with UDP we don’t have to take care about client connections.

using System;
using Microsoft.SPOT;
using System.Net.Sockets;
using System.Threading;
using System.Net;

namespace UdpServerExample
{
    public class UdpSocketServer
    {
        public const int DEFAULT_SERVER_PORT = 8080;

        private int port;
        private Socket socket;

        public delegate void DataReceivedEventHandler(object sender, DataReceivedEventArgs e);
        public event DataReceivedEventHandler DataReceived;

        public UdpSocketServer()
            : this(DEFAULT_SERVER_PORT)
        { }

        public UdpSocketServer(int port)
        {
            this.port = port;
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        }

        public void Start()
        {
            new Thread(StartServerInternal).Start();
        }

        private void StartServerInternal()
        {
            EndPoint endPoint = new IPEndPoint(IPAddress.Any, port);
            socket.Bind(endPoint);

            while (true)
            {
                if (socket.Poll(-1, SelectMode.SelectRead))
                {
                    byte[] buffer = new byte[socket.Available];
                    int bytesRead = socket.ReceiveFrom(buffer, ref endPoint);

                    DataReceivedEventArgs args = new DataReceivedEventArgs(endPoint, buffer);
                    OnDataReceived(args);

                    if (args.ResponseData != null)
                        socket.SendTo(args.ResponseData, endPoint);
                }
                else
                {
                    Thread.Sleep(10);
                }
            }
        }

        private void OnDataReceived(DataReceivedEventArgs e)
        {
            if (DataReceived != null)
                DataReceived(this, e);
        }

        public static string BytesToString(byte[] bytes)
        {
            int length = bytes.Length;
            char[] text = new char[length];
            for (int i = 0; i < length; i++)
                text[i] = (char)bytes[i];

            return new string(text);
        }
    }
}

To use the UdpServerSocket class, we need to indicate the port to listen on. If not specified, the default is 8080. In the constructor, a Socket object is created using the UDP protocol type. The UdpServerSocket.Start method creates a new thread that waits for messages (the separate thread is necessary in order not to block the application).

When data are available, we read them using the Socket.ReceiveFrom method. Then, we create an object of type DataReceivedEventArgs, using the sender endpoint and the received bytes. Finally, we call OnDataReceveid method, that in turn raises the DataReceived event, by which the application is notified about the arrival of new data.

If the class that handles the DataReceived event (as we’ll see later) assigns a value to the ResponseData property of the DataReceivedEventArgs object, the byte array will be automatically sent to the client.

Here is the DataReceivedEventArgs class:

public class DataReceivedEventArgs : EventArgs
{
    public EndPoint RemoteEndPoint { get; private set; }
    public byte[] Data { get; private set; }
    public byte[] ResponseData { get; set; }

    public DataReceivedEventArgs(EndPoint remoteEndPoint, byte[] data)
    {
        RemoteEndPoint = remoteEndPoint;
        if (data != null)
        {
            Data = new byte[data.Length];
            data.CopyTo(Data, 0);
        }
    }
}

Using the UdpServerSocket Class

Now we’ll show how to use the UdpServerSocket class.  Create a .NET Gadgeteer application and connect the following modules to the FEZ Spider mainboard:

The result system is shown in the following screenshot:

UDP Server test device application

UDP Server test device application

Let’s insert the inizialization code in the ProgramStarted method:

private const string SSID = "YOUR_NETWORK_SSID";
private const string PASSPHRASE = "YOUR_NETWORK_PASSPHRASE";

private UdpSocketServer udpServer;

// This method is run when the mainboard is powered up or reset.
void ProgramStarted()
{
    udpServer = new UdpSocketServer(8080);
    udpServer.DataReceived += new UdpSocketServer.DataReceivedEventHandler(udpServer_DataReceived);

    Gadgeteer.Modules.GHIElectronics.WiFi_RS21.WiFiNetworkInfo info = new WiFi_RS21.WiFiNetworkInfo();
    info.SSID = SSID;
    info.SecMode = WiFi_RS21.SecurityMode.WPA2;
    info.networkType = WiFi_RS21.NetworkType.AccessPoint;

    wifi.NetworkUp += new GTM.Module.NetworkModule.NetworkEventHandler(wifi_NetworkUp);

    wifi.UseDHCP();
    wifi.Join(info, PASSPHRASE);

    // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
    Debug.Print("Program Started");
}

We create an instance of UpdSocketServer that waits for messages on port 8080. We then register the DataReceveid event. Finally, we configure the Wi-Fi connection.

When network is available, we show the IP address on the display and we start the UDP Socket Server:

private void wifi_NetworkUp(GTM.Module.NetworkModule sender, GTM.Module.NetworkModule.NetworkState state)
{
    oledDisplay.SimpleGraphics.Clear();
    oledDisplay.SimpleGraphics.DisplayText(wifi.NetworkSettings.IPAddress,
        Resources.GetFont(Resources.FontResources.NinaB), GT.Color.Yellow, 15, 50);

    udpServer.Start();
}

As said before, when data arrive, the DataReceived event is raised:

private void udpServer_DataReceived(object sender, DataReceivedEventArgs e)
{
    string receivedMessage = UdpSocketServer.BytesToString(e.Data);

    var font = Resources.GetFont(Resources.FontResources.small);
    oledDisplay.SimpleGraphics.ClearNoRedraw();
    oledDisplay.SimpleGraphics.DisplayText("Message from",
        font, GT.Color.Yellow, 0, 20);
    oledDisplay.SimpleGraphics.DisplayText(e.RemoteEndPoint.ToString(),
        font, GT.Color.Yellow, 0, 35);
    oledDisplay.SimpleGraphics.DisplayText(receivedMessage,
       font, GT.Color.Yellow, 0, 60);

    // Creates a response and assigns it to the DataReceivedEventArgs.ResponseData property, so that
    // it will be automtically sent to client.
    string response = "Response from server for the request '" + receivedMessage + "'";
    e.ResponseData = System.Text.Encoding.UTF8.GetBytes(response);
}

We use the BytesToString utility function to retrieve the string from the received bytes, and we print the message to the display.

Next, we create a message and assign it to the ResponseData property of DataReceivedEventArgs: as shown earlier, this is the way to specify a response to send to the client.

A client for our Server

In order to test our server, we need a client application that can send requests. We therefore create a Console Application:

class Program
{
    const string SERVER_IP = "192.168.1.104";
    const int SERVER_PORT = 8080;

    static void Main(string[] args)
    {
        UdpClient client = new UdpClient();
        Console.Write("Connecting... ");

        // The connect method doesn't perform a real connection, but it simply set a default
        // remote host for any subsequent operation.
        client.Connect(SERVER_IP, SERVER_PORT);
        Console.WriteLine("Connected\n");

        //IPEndPoint object will allow us to read datagrams sent from any source.
        IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

        while (true)
        {
            Console.Write("Enter a string and press ENTER (empty string to exit): ");

            string message = Console.ReadLine();
            if (string.IsNullOrEmpty(message))
                break;

            byte[] data = Encoding.Default.GetBytes(message);
            Console.WriteLine("Sending... ");

            client.Send(data, data.Length);

            byte[] responseBytes = client.Receive(ref remoteIpEndPoint);
            string response = string.Format("Response from {0}:{1}: {2}",
                remoteIpEndPoint.Address, remoteIpEndPoint.Port,
                Encoding.Default.GetString(responseBytes, 0, responseBytes.Length));

            Console.WriteLine(response);
            Console.WriteLine();
        }
    }
}

The only modification necessary to use this application is to change the SERVER_IP constant based on IP address that is assigned to the .NET Gadgeteer application. Note that the UdpClient.Connect method doesn’t perform a real connection, because as said before the UDP protocol is connectionless. Instead, it simply specify a default remote host to which all the subsequent messages are sent. All the rest of the code is quite self-explanatory.

Both the applications are available for download.

UdpServerExample.zip

, ,

  1. What are people doing with .NET Gadgeteer? | MSDN Blogs

Leave a comment