使用UWP DatagramSocket和Socket API的UDP吞吐量性能较差

K S*_*ngh 5 c# sockets networking udp uwp

我有一个基本的C#.NET UDP服务器和客户端代码,我正在尝试将其移植到UWP.对于UWP,我尝试使用DatagramSocket和常规Socket类.我看到使用DatagramSocket类在UWP服务器上传入的UDP数据包上有近40%的数据包丢失.如果我使用UWP套接字,我看到丢包率约为70%.旧的.NET代码显示0%的数据包丢失.

我想也许我没有正确使用UWP API,因此我的性能很差.有人可以指导我如何提高UWP服务器性能吗?

现在,所有测试都是使用环回完成的.UWP默认情况下不允许环回,因此我按照此处提到的说明启用环回.

服务器在50000端口上侦听数据包,客户端代码从50001向服务器发送大约60字节的数据包.

C#.NET客户端代码如下:

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());
}
Run Code Online (Sandbox Code Playgroud)

C#.NET服务器代码:

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());
}
Run Code Online (Sandbox Code Playgroud)

使用上面的代码,我看到在服务器上收到的所有10000个数据包.

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));
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

UWP套接字代码:

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);
        } 
    }
}
Run Code Online (Sandbox Code Playgroud)

我在github上发布了完整的源代码: