我的异步 TcpListener 有时会得到 CPU 50-60% 的负载

My async TcpListener getting my CPU 50-60% load sometimes

我被这个严重的问题困住了。

我有异步 TcpListener。有时有几个连接的客户端,一切都很好。有时即使只有一个人。服务器开始使用我 CPU.

的 50-60%

我认为问题可能在于处理读取异常,但这是我唯一的提示,我不知道如何测试它。

这是服务器的代码:

class Server
{
    private TcpListener server;

    public Server(string hostname, int port = 25000)
    {
        server = new TcpListener(IPAddress.Parse(hostname), port);
    }

    public void ServerStart()
    {
        server.Start();
        WaitForClientConnect();
    }

    private async void WaitForClientConnect()
    {
        TcpClient client = await server.AcceptTcpClientAsync();
        Console.WriteLine("The async connection created for: " + ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());

        OnClientConnect(client);
    }

    private void OnClientConnect(TcpClient client)
    {
        ClientLowAPI clientReq = new ClientLowAPI(client);

        WaitForClientConnect();
    }
}

这是处理单个客户端的代码:

class ClientLowAPI
{
    private TcpClient client;
    private NetworkStream stream;

    public ClientLowAPI(TcpClient clientConnected)
    {
        client = clientConnected;
        stream = client.GetStream();
        WaitForHeader();
    }

    private async void WaitForHeader()
    {
        byte[] buffer = new byte[4];

        int bytesRead = 0;
        while (bytesRead < 4)
        {
            try
            {
                bytesRead += await stream.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead);
            }
            catch
            {
                stream.Close();
                client.Close();
                return;
            }
        }

        WaitForData(FourBytesToInt(buffer));
    }

    private async void WaitForData(int length)
    {
        byte[] buffer = new byte[length];

        int bytesRead = 0;
        while (bytesRead < length)
        {
            try
            {
                bytesRead += await stream.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead);
            }
            catch
            {
                stream.Close();
                client.Close();
                return;
            }
        }

        ExecuteMessage(buffer);
    }

    private void ExecuteMessage(byte[] binaryData)
    {
        // Do something with message
        WaitForHeader();
    }

    public async void SendMessage(byte[] message)
    {
        byte[] buffer = new byte[message.Length + 4];
        byte[] length = IntToFourBytes(message.Length);

        length.CopyTo(buffer, 0);
        message.CopyTo(buffer, 4);

        try
        {
            await stream.WriteAsync(buffer, 0, buffer.Length);
        }
        catch
        {
            stream.Close();
            client.Close();
            return;
        }
    }

    private int FourBytesToInt(byte[] array)
    {
        int res = 0;
        res += array[0] * 256 * 256 * 256;
        res += array[1] * 256 * 256;
        res += array[2] * 256;
        res += array[3];
        return res;
    }

    private byte[] IntToFourBytes(int intValue)
    {
        byte[] array = new byte[4];
        array[0] = (byte)(intValue >> 24);
        array[1] = (byte)(intValue >> 16);
        array[2] = (byte)(intValue >> 8);
        array[3] = (byte)intValue;
        return array;
    }
}

问题是由这个循环引起的:

while (bytesRead < 4)
        {
            try
            {
                bytesRead += await stream.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead);
            }
            catch
            {
                stream.Close();
                client.Close();
                return;
            }
        }

通常是连接被强制终止并且服务器引发了异常,但有时客户端通过 TcpClient.Close() 正确关闭了连接,然后没有引发异常并且 stream.ReadAsync 方法开始 returns 0 导致无限循环,使用量巨大 CPU。

为了快速修复,我使用了以下条件:

        if (bytesRead == 0)
        {
            throw new System.IO.IOException();
        }