How to Create a UDP Server in C#

Saad Aslam Feb 02, 2024
How to Create a UDP Server in C#

This article will show how you can create a simple UDP server in C#.

Create a UDP Server in C#

For a brief background, the UDP protocol does not need to build a connection with the client. The data is just transmitted without authenticating whether the client received it or not.

This type of protocol is usually used for broadcasting the data. Because UDP is connectionless, a listener doesn’t need to be online to receive the message.

To transmit a datagram with UDP, you’ll need to know the network address of the network device that hosts the service and the service’s UDP port number. Port numbers for popular services are defined by the Internet Assigned Numbers Authority (IANA); the range of port numbers is 1,024 to 65,535 and can be assigned to services that are not on the IANA list.

On IP-based networks, special network addresses are used to handle UDP broadcast messages. The following explanation utilizes the Internet’s IP version 4 address family as an example.

By setting all bits of the host identification, broadcasts may be directed to specified parts of a network. Use the address 192.168.1.255 to broadcast to all hosts on the network with IP addresses that begin with 192.168.1.

We are now ready to build or create a socket, set up our UDP protocol, and start the communication immediately.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

These would be the libraries used for setting up the server. These libraries support all the basic functionality related to networking, such as building sockets, handling the IPV4 addresses, and many more.

public class SimpleUdpSrvr {
  public static void Main() {
    int recv;
    byte[] data = new byte[1024];
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
    Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  }
}

The int recv line creates a recv variable of integer type that contains the number of bytes of the string message the client received.

The byte[] data = new byte[1024]; line is used to create an array named data of byte size for each cell with 1024 cells, also called array size. This array is created dynamically in a heap.

The IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050); line tells that to create a ipep variable for the socket. The information passing in it tells what kind of socket it should use.

The IPEndPoint class represents a network endpoint with an IP address and port number; the client needs this configuration information to connect with our service. The IPAddress.Any argument passing in is telling that server may connect with any IP address to the 9050 port number; the ipep variable is also created dynamically.

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

This line creates a newsock variable, a socket for us through which we will communicate. The arguments passing in it tell what kind of socket we want to create.

The AddressFamily.InterNetwork tells us we want the local IP addresses. The SocketType.Dgram argument states that the data should flow in datagrams instead of packets.

And lastly, the ProtocolType.Udp argument tells the protocol type of the socket we will use. Now, our socket is created.

newsock.Bind(ipep);
Console.WriteLine("Waiting for a client...");

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(sender);

Until now, we had created our one endpoint in the network, and a socket through which we will communicate, newsock.Bind(ipep); line will now help us bind our endpoint to the socket.

ipep is the variable that has the information about our endpoint and is passed in the bind() function of our newsock object.

Console.WriteLine("Waiting for a client...");

This line prints on the screen that the server is waiting for the client to send any message. We need to create another endpoint for the sender that will try to communicate with the server.

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

This line creates another endpoint, and the variable is called sender. The argument passed in its IPAddress.Any tells that we are expecting any IP address, and 0 means that it is a wild card for the port number, and the system should see and find any suitable port allot it to us.

The EndPoint Remote = (EndPoint)(sender); line is used to find the sender’s IP address and store it in the remote variable.

recv = newsock.ReceiveFrom(data, ref Remote);

Console.WriteLine("Message received from {0}:", Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

The recv variable that we made at the start of our program is now used in the recv = newsock.ReceiveFrom(data, ref Remote); line. We use the Receive() function of the socket we created earlier, newsock, and currently receive all the data we have in the socket at that time.

The arguments passing the Receive() function tell where to store the data and who’s data should be stored or is expected. The data argument is the byte size array being passed, and data will be written data array.

The ref Remote argument tells that that IP address sent the data, and the function will return the number of bytes fetched from that socket and store it into the recv variable.

Console.WriteLine("Message received from {0}:", Remote.ToString());

This line writes on the screen the IP address of the client that sent the data through the socket. The argument passed Remote.ToString() converts the decimal numbers into the ASCII characters, and the remote variable was the second endpoint referring to the client.

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

This line writes the actual data on the screen. The data sent through the socket is in the raw form and should be converted into ASCII characters to read.

The Encoding.ASCII.GetString(data, 0, recv) line takes the data from the data variable that is passed as an argument, and the recv argument (contains the number of bytes that client sent) tells that to write these many bytes from the data variable on the screen.

string welcome = "Welcome to my test server";
data = Encoding.ASCII.GetBytes(welcome);
newsock.SendTo(data, data.Length, SocketFlags.None, Remote);

The string welcome = "Welcome to my test server"; line initialize the welcome string variable with the Welcome to my test server text.

The data = Encoding.ASCII.GetBytes(welcome); line takes the welcome variable as an argument in the Encoding.ASCII.GetBytes() function and converts it into the raw form, so it is ready to send through the socket at the other end.

newsock.SendTo(data, data.Length, SocketFlags.None, Remote);

This line sends the data through our previously created socket newsock and uses the Send() function. The arguments it takes are: the data variable containing the raw form of data to be sent, the data.Length argument telling how many bytes to write on the socket as the length of the data is equivalent to the number of bytes, the SocketFlags.None argument telling us to keep all the flags zero, the flags are indicators, and every flag has its meaning.

The Remote variable argument tells us about the client we want to send the data to as the Remote variable stores the client’s IP address and port number.

while (true) {
  data = new byte[1024];
  recv = newsock.ReceiveFrom(data, ref Remote);

  Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
  newsock.SendTo(data, recv, SocketFlags.None, Remote);
}

The while(true) line tells that it is an infinite loop and that all its statements will run infinitely. The data = new byte[1024]; line creates a new byte size array of length 1024 whenever it is executed.

The recv = newsock.ReceiveFrom(data, ref Remote); line receives the data from the client and saves it to the data array.

The Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv)); writes the data on the screen.

The newsock.SendTo(data, recv, SocketFlags.None, Remote); line sends back the same data to the client that the server has received from it.

After that, the server will again stop and wait for the client, and whatever the client sends to the server will respond with the same message. This server will never terminate unless it crashes or the user stops it manually.

Now, as we have learned how to create a UDP server in C# and its basic functionalities, we can add more functionality and make a server according to our requirements.

Complete Source Code:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class SimpleUdpSrvr {
  public static void Main() {
    int recv;
    byte[] data = new byte[1024];
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);

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

    newsock.Bind(ipep);
    Console.WriteLine("Waiting for a client...");

    IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
    EndPoint Remote = (EndPoint)(sender);

    recv = newsock.ReceiveFrom(data, ref Remote);

    Console.WriteLine("Message received from {0}:", Remote.ToString());
    Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

    string welcome = "Welcome to my test server";
    data = Encoding.ASCII.GetBytes(welcome);
    newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
    while (true) {
      data = new byte[1024];
      recv = newsock.ReceiveFrom(data, ref Remote);

      Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
      newsock.SendTo(data, recv, SocketFlags.None, Remote);
    }
  }
}
Author: Saad Aslam
Saad Aslam avatar Saad Aslam avatar

I'm a Flutter application developer with 1 year of professional experience in the field. I've created applications for both, android and iOS using AWS and Firebase, as the backend. I've written articles relating to the theoretical and problem-solving aspects of C, C++, and C#. I'm currently enrolled in an undergraduate program for Information Technology.

LinkedIn

Related Article - Csharp Server