Poor UDP throughput performance using UWP DatagramSocket & Socket APIs

Viewed 483

I have a basic C#.NET UDP server and client code and I am trying to port it to UWP. For UWP, I experimented with DatagramSocket and regular Socket class. I am seeing almost 40% packet drops on incoming UDP packets on UWP Server using DatagramSocket class. If I use UWP Sockets, I see the packet loss of around 70%. The old .NET code shows 0% packet loss.

I am thinking maybe I am not using the UWP APIs correctly and hence I am getting poor performance. Could someone guide me on how to improve UWP server performance?

Right now, all the tests are done using loop-back. UWP doesn't allow loop-back by default so I am followed the instructions mentioned here to enable loop-back.

The server listens for packet on 50000 port and Client code sends packets of around 60 bytes to server from 50001.

The C#.NET client code is below:

try
{
    byte[] buffer = new byte[1024];

    IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 50001);
    IPAddress remoteIp = System.Net.IPAddress.Parse("127.0.0.1");
    IPEndPoint remoteEP = new IPEndPoint(remoteIp, 50000);

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

    try
    {
        sender.Bind(localEP);

        for(int i = 0; i < 10000; i++)
        {
            //Thread.Sleep(1);
            // Encode the data string into a byte array. 
            string ClientReq =  "Client Request:: " + i.ToString() + " "+ Guid.NewGuid().ToString();
            byte[] msg = Encoding.ASCII.GetBytes(ClientReq);

            // Send the data through the socket.  
            int sentBytes = sender.SendTo(msg, remoteEP);
            Console.WriteLine("{0}::{1} Client Request ({2} bytes):: {3}.",
            remoteEP.Address.ToString(),
            remoteEP.Port.ToString(),
            sentBytes,
            ClientReq
            );

        }

        // Release the socket.  
        sender.Close();
        //Console.ReadKey();

    }
    catch(ArgumentNullException ane)
    {
        Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
    }
    catch(SocketException se)
    {
        Console.WriteLine("SocketException : {0}", se.ToString());
    }
    catch(Exception e)
    {
        Console.WriteLine("Unexpected exception : {0}", e.ToString());
    }

}
catch(Exception e)
{
    Console.WriteLine(e.ToString());
}

C#.NET Server Code:

byte[] buffer = new Byte[1024];

IPAddress LocalIp = IPAddress.Any; //System.Net.IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(LocalIp, 50000);

// Create a UDP/IP socket.  
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );

// Bind the socket to the local endpoint and   
// listen for incoming connections.  
try
{
    listener.Bind(localEndPoint);
    Console.WriteLine("Bind Complete");

    int messagesReceived = 0;

    while(true)
    {

        EndPoint receiveEP = new IPEndPoint(IPAddress.Any, 0);
        int receivedBytes = listener.ReceiveFrom(buffer, ref receiveEP);

        messagesReceived++;

        IPEndPoint receiveIPEP = receiveEP as IPEndPoint;
        Console.WriteLine("{0}::{1}::{2} Client Request ({3} bytes):: {4}.",
            messagesReceived,
            receiveIPEP.Address.ToString(),
            receiveIPEP.Port.ToString(),
            receivedBytes,
            System.Text.Encoding.UTF8.GetString(buffer, 0, receivedBytes));

    }
}
catch(Exception e)
{
    Console.WriteLine(e.ToString());
}

With this above code, i see all the 10000 packets are received at server.

UWP DatagramSocket Code:

DgSocket = new DatagramSocket();

DgSocket.MessageReceived += SocketListener_MessageReceived;

await DgSocket.BindServiceNameAsync("50000");

private async void SocketListener_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
     uint datalen = args.GetDataReader().UnconsumedBufferLength;

    DataReader reader = args.GetDataReader();
    byte[] dataBuffer = new byte[reader.UnconsumedBufferLength];
    reader.ReadBytes(dataBuffer);

    await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        lock(_lockObject)
        {
            DgPackets++;
            DgPacketList.Add(Encoding.ASCII.GetString(dataBuffer));
        }
    });
}

UWP Socket Code:

public void SetupSimpleSocketListener()
{
    try
    {
        IPAddress LocalIp = IPAddress.Any;
        IPEndPoint localEndPoint = new IPEndPoint(LocalIp, 50000);
        SimpleSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );

        byte[] buffer = new Byte[1024];
        SimpleSocket.Bind(localEndPoint);
        Debug.WriteLine("Bind Complete");

        SocketAsyncEventArgs sockarg = new SocketAsyncEventArgs();
        sockarg.Completed += Sockarg_Completed;
        sockarg.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
        sockarg.SetBuffer(buffer, 0, buffer.Length);

        if(!SimpleSocket.ReceiveFromAsync(sockarg))
        {
            Sockarg_Completed(this, sockarg);
        }
    }
    catch(Exception e)
    {
        Debug.WriteLine(e.ToString());
    }    
}

private async void Sockarg_Completed(object sender, SocketAsyncEventArgs e)
{
    await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        lock(_lockObject)
        {
            SimpleSocketPackets++;
            SimpleSocketPacketList.Add(Encoding.ASCII.GetString(e.Buffer, 0, e.BytesTransferred));
        }
    });

    if(e.SocketError == System.Net.Sockets.SocketError.Success)
    {
        if(!SimpleSocket.ReceiveFromAsync(e))
        {
            Sockarg_Completed(this, e);
        } 
    }
}

I have posted the full source code on github:

0 Answers
Related