我的异步TcpListener有时会使我的CPU加载50-60%

时间:2017-10-16 13:25:05

标签: c# async-await tcplistener

我遇到了这个严重的问题。

我有异步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;
    }
}

1 个答案:

答案 0 :(得分:1)

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

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

通常是强制连接被杀死,服务器引发了异常,但有时客户端通过TcpClient.Close()正确关闭了连接,然后没有引发异常,并且stream.ReadAsync方法启动返回0,这导致了巨大的无限循环CPU使用率。

对于快速修复,我使用以下条件:

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