C#UDP服务器循环最大CPU

时间:2014-02-23 16:41:11

标签: c# performance sockets udp cpu-usage

我已经看过谷歌的所有内容,甚至在Stack溢出,但我似乎无法找到我正在寻找的解决方案。我正在测试我的编程技巧,使用MonoGame for C#重新制作Pong,我正试图用UDP客户端和UDP服务器制作这个多人游戏。我将使用“完美的客户端 - 服务器模型”的想法,服务器处理所有计算,而游戏客户端只是从服务器接收数据并将其显示在屏幕上。不幸的是,我曾经遇到过编程UDP服务器的问题。我有一个循环,我收到一个数据报,而不是开始听另一个。我使用异步调用,因为在我看来,这对客户端和服务器最有效。 代码看起来像这样:(我将删除不会影响CPU的位,并仅显示网络。)

    static void Main()
    {
        //Initialize
        Console.Title = "Pong Server";
        Console.WriteLine("Pong Server");
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

        //Bind socket
        EndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 25565);
        Console.WriteLine("Binding to port 25565");
        serverSocket.Bind(localEndPoint);

        //Listen
        Console.WriteLine("Listening on {0}.", localEndPoint);

        //Prepare EndPoints
        EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);

        //Recive Data...
        rcvPacket = new byte[Data.Size];
        serverSocket.BeginReceiveFrom(rcvPacket, 0, Data.Size, SocketFlags.None, ref clientEndPoint, new AsyncCallback(Receive), null);
    }

然后在接收(IAsyncResult ar)方法:

    static void Receive(IAsyncResult ar)
    {
        //Prepare EndPoints
        EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);

        //End
        int PacketSize = serverSocket.EndReceiveFrom(ar, ref clientEndPoint);

        //<Handle Packet Code Here>

        //Receive Loop
        rcvPacket = new byte[Data.Size];
        serverSocket.BeginReceiveFrom(rcvPacket, 0, Data.Size, SocketFlags.None, ref clientEndPoint, new AsyncCallback(Receive), null);
    }

这段代码看起来是等待收到数据包,而不是监听另一个数据包,这将停止这个“侦听器”线程,这是异步的。无论如何,感谢您阅读我的问题,希望我能深究这一点。

哦顺便说一句,这是我的4个核心之一的图像被最大化了。 (是的,我正在调试它。) Debugging Pong Server.exe; Maxing one of 4 CPU Cores

2 个答案:

答案 0 :(得分:1)

添加 Thread.Sleep(1)调用更新循环不仅修复了原始问题中的CPU使用率,而且还使更新循环中执行的代码表现得更好。在 while(alive)} {} 里面,我记录了已用时间和总时间,我插入了睡眠通话。

似乎需要至少1

0 CPU Usage!

    static void Main(string[] args)
    {
        //Initialize
        Console.Title = "Pong Server";
        Console.WriteLine("Pong Server");
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

        //Bind socket
        EndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 25565);
        Console.WriteLine("Binding to port 25565");
        serverSocket.Bind(localEndPoint);

        //Listen
        Console.WriteLine("Listening on {0}.", localEndPoint);

        //Prepare EndPoints
        EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);

        //Recive Data...
        serverSocket.BeginReceiveFrom(rcvPacket, 0, Data.Size, SocketFlags.None, ref clientEndPoint, new AsyncCallback(ReceiveFrom), null);

        //Initialize TimeSpans
        DateTime Now = DateTime.Now;
        DateTime Start = Now;
        DateTime LastUpdate = Now;
        TimeSpan EllapsedTime;
        TimeSpan TotalTime;

        //Create Physics Objects
        Paddle1 = new Physics2D();
        Paddle2 = new Physics2D();
        Ball = new Physics2D();

        //Loop
        while (alive)
        {
            Now = DateTime.Now;
            TotalTime = Now - Start;
            EllapsedTime = Now - LastUpdate;
            LastUpdate = Now;
            Update(EllapsedTime, TotalTime);

            //Add Sleep to reduce CPU usage;
            Thread.Sleep(1);
        }

        //Press Any Key
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

答案 1 :(得分:-1)

来自MSDN文档:

  

您的回调方法应调用 EndReceiveFrom 方法。当您的应用程序调用BeginReceiveFrom时,系统将使用单独的线程来执行指定的回调方法,并且它将在EndReceiveFrom上阻塞,直到Socket读取数据或引发异常。如果希望在调用BeginReceiveFrom方法后阻止原始线程,请使用WaitHandle.WaitOne。如果希望原始线程继续执行,请在回调方法中调用T:System.Threading.ManualResetEvent上的Set方法。有关编写回调方法的其他信息,请参阅回调示例

根据我的理解,您在调用BeginReceiveFrom时直接创建回调线程。 因为你没有使用EndReceiveFrom,你执行回调线程,一次又一次地创建另一个线程......

使用EndReceiveFrom等待读取整个数据包,然后您的回调将重复并再次开始读取。注意线程安全我不知道你如何管理你的数据。

查看该帖子可能会有所帮助: Asynchronous TCP/UDP Server