I have a basic C # .NET UDP server and client code, and I'm trying to port it to UWP. For UWP, I experimented with a DatagramSocket and the regular Socket class. I see almost 40% of packet drops on incoming UDP packets on the UWP server using the DatagramSocket class. If I use UWP sockets, I see that packet loss is about 70%. Old .NET code shows packet loss at 0%.
I think that I am not using the UWP API correctly and therefore getting poor performance. Can someone help me improve the performance of the UWP server?
Currently, all tests are performed using feedback. UWP does not allow default bindings, so I follow the instructions given here to enable loop-back.
The server listens for the packet on port 50,000, and the client code sends packets of 60 bytes to the 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()); }
.NET.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()); }
Using this code above, I see that all 10,000 packets are received on the 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 posted the full github source code: