Base of The PostSharp UDP Communication Aspect

Hi, Today I would like to show how Simple is communicate via network UDP. I sometimes saw how some developers try prepare those kind of communication with more code. In C# that can be very easy. I would like to only show you an example. And ask you is it enough to communication? Of course it is class that can be very easy used as base of the PostSharp Communication Aspect. I think that you can easily encapsulate that code into an aspect ;).

namespace UdpCommunicationExample
{
  using System;
  using System.Diagnostics;
  using System.Net;
  using System.Net.Sockets;
  using System.Threading;
  using System.Runtime.CompilerServices;
  using System.Threading.Tasks;
  
  public class UdpCommunicationClient
  {
    private readonly UdpClient udpClient;
 
    public UdpCommunicationClient(IPEndPoint clientIpEndPoint) {
      udpClient = new UdpClient(clientIpEndPoint);
    }
 
    [MethodImpl(MethodImplOptions.Synchronized)]
    public bool SendData(byte[] datagram, IPEndPoint serverIpEndPoint) {
      lock (this) {
        while (!udpClient.Client.Poll(100, SelectMode.SelectWrite))
          ;
        var asyncResult = udpClient.BeginSend(
          datagram, datagram.Length,
          serverIpEndPoint, null, null);
        asyncResult.AsyncWaitHandle.WaitOne(Timeout.Infinite);
 
        return datagram.Length == udpClient.EndSend(asyncResult);
      }
    }
  }
 
  public class UdpCommunicationServer
  {
    private readonly UdpClient udpClientListener;
 
    public delegate void UdpCommunicatorDatagramReceived(byte[] datagram);
    public event UdpCommunicatorDatagramReceived DatagramReceived;
 
    public UdpCommunicationServer(IPEndPoint serverIpEndPoint) {
      udpClientListener = new UdpClient(serverIpEndPoint);
      new Thread(StartUdpListener) { IsBackground = true }.Start();
    }
 
    private void StartUdpListener() {
      do {
        IPEndPoint ipEndPoint = null;
        var asyncResult = udpClientListener.BeginReceive(null, null);
        asyncResult.AsyncWaitHandle.WaitOne(Timeout.Infinite);
        var datagram = udpClientListener.EndReceive(asyncResult, ref ipEndPoint);
        DatagramRecived(datagram);
      } while (true);
    }
 
    private void DatagramRecived(byte[] datagram) {
      if (DatagramReceived != null)
        DatagramReceived(datagram);
    }
  }
 
  public class Program
  {
    static void Main() {
      var serverIpEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2000);
      var clientIpEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.2"), 2000);
      var udpComunicationServer = new UdpCommunicationServer(serverIpEndPoint);
      var udpComunicationClient = new UdpCommunicationClient(clientIpEndPoint);
 
      var packetCount = 0;
 
      udpComunicationServer.DatagramReceived +=
        datagram => Interlocked.Increment(ref packetCount);
 
      var stopwatch = Stopwatch.StartNew();
      Parallel.For(0, 20000, i => {
        udpComunicationClient
          .SendData(new byte[] { 1,2,3,4,5,6,7,8,9,10 }, serverIpEndPoint);
        udpComunicationClient
          .SendData(new byte[] { 2,2,3,4,5,6,7,8,9,10 }, serverIpEndPoint);
        udpComunicationClient
          .SendData(new byte[] { 3,2,3,4,5,6,7,8,9,10 }, serverIpEndPoint);
        udpComunicationClient
          .SendData(new byte[] { 4,2,3,4,5,6,7,8,9,10 }, serverIpEndPoint);
        udpComunicationClient
          .SendData(new byte[] { 5,2,3,4,5,6,7,8,9,10 }, serverIpEndPoint);
      });
      stopwatch.Stop();
 
      Thread.Sleep(4);
 
      Console.WriteLine(@"Sending {0} tivial UDP packets takes about {1} ms.",
        packetCount,
        stopwatch.ElapsedMilliseconds);
 
      Console.ReadKey();
    }
  }
}

So in my PC an output is:

Sending 100000 trivial UDP packets takes about 4693 ms.

What do you think is it 469 ms is enough for 10 000 parallel packets? Why most of developers write more code in those kind of solutions?

Ok so, that I will change my solutions a bit to something worst.

[MethodImpl(MethodImplOptions.Synchronized)]
public bool SendData(byte[] datagram, IPEndPoint serverIpEndPoint) {
  lock (this) {
    while (!udpClient.Client.Poll(100, SelectMode.SelectWrite))
      ;
    return datagram.Length == udpClient.Send(
      datagram, datagram.Length,
      serverIpEndPoint);
  }
}
private void StartUdpListener() {
  do {
    IPEndPoint ipEndPoint = null;
    var datagram = udpClientListener.Receive(ref ipEndPoint);
    DatagramRecived(datagram);
  } while (true);
}

And after that changes everything looks very cool and an output is:

Sending 100000 trivial UDP packets takes about 2358 ms.

p ;).

Leave a Reply

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

*