TCP服务器CPU占用率高

本文关键字:占用率 CPU 服务器 TCP | 更新日期: 2023-09-27 17:50:32

c# Visual Studio 2013

我正在做一个粗略的TCP服务器/客户端。它是这样工作的:
客户端向服务器发送消息,服务器向客户端发送"响应"。当我要在游戏中的多人游戏中使用这种数据传输时,我将在循环中使用它。但是,我进行了性能测试,因为当超过三个客户机连接时,我的TCP服务器使用了大量CPU。性能分析器表示,以下方法的利用率为96%。你能帮我修一下吗?

private static void ReceiveCallback(IAsyncResult AR)
    {
        Socket current = (Socket)AR.AsyncState;
        int received;
        try
        {
            received = current.EndReceive(AR);
        }
        catch (SocketException)
        {
            Console.WriteLine("Client forcefully disconnected");
            current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
            _clientSockets.Remove(current);
            return;
        }
        byte[] recBuf = new byte[received];
        Array.Copy(_buffer, recBuf, received);
        string text = Encoding.ASCII.GetString(recBuf);
        Console.WriteLine("Received Text: " + text);

        string msg = "Response!";
        byte[] data = Encoding.ASCII.GetBytes(msg);
        current.Send(data);

        current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
    }

以防万一,这里是调用ReceiveCallback的AcceptCallback方法。

private static void AcceptCallback(IAsyncResult AR)
    {
        Socket socket;
        try
        {
            socket = _serverSocket.EndAccept(AR);
        }
        catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
        {
            return;
        }
        _clientSockets.Add(socket);
        socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
        Console.WriteLine("Client connected...");
        _serverSocket.BeginAccept(AcceptCallback, null);
    } 

TCP服务器CPU占用率高

在评论中,你说你的代码发送数据的速度是CPU和网络允许的,但你想节流。你可能应该考虑你想要发送的最佳频率是多少。然后,以该频率发送。

var delay = TimeSpan.FromMilliseconds(50);
while (true) {
 await Task.Delay(delay);
 await SendMessageAsync(mySocket, someData);
 await ReceiveReplyAsync(mySocket);
}

注意,我已经使用了await来解开回调的混乱。如果现在在混合中添加计时器或延迟,回调可能会变得笨拙。不过,你可以用任何你喜欢的方式来做。或者,您只需在后台线程/任务上使用同步套接字IO。如果没有太多的线程,这甚至是更简单和首选的方法。请注意,MSDN通常没有很好的理由使用套接字的APM模式。

注意,Thread.Sleep/Task。如果你想基于时间等待,那么使用Delay是完全可以的。

你为什么要这样做:

byte[] recBuf = new byte[received];
Array.Copy(_buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);

你有一个复制操作,复制你收到的缓冲区在recBuf,然后另一个创建字符串。你可以避免一个,你的表现就会提高。但是cpu高的事实是正常的,因为即使转换为字符串也会使用cpu。