async await usage with TcpClient

11,568

Solution 1

I ended up using length-prefixed messages, prefixing every packet by 4 bytes representing the length of the data to come.

Solution 2

The TcpClient.Connected value is not updated immediately. According to MSDN:

true if the Client socket was connected to a remote resource as of the most recent operation; otherwise, false.

So having TcpClient.Connected as a while loop condition is not a good choice.

TcpClient.DataAvailable is used for synchronous operations and do not used for asynchronous.

Update your code to:

static async void ReadAsync(TcpClient client)
{
    NetworkStream ns = client.GetStream();
    MemoryStream ms = new MemoryStream();
    byte[] buffer = new byte[1024];

    while(true) {
        int bytesRead = await ns.ReadAsync(buffer, 0, buffer.Length);
        if (bytesRead <= 0)
            break;
        ms.Write(buffer, 0, bytesRead);
        HandleMessage(ms.ToArray());
        ms.Seek(0, SeekOrigin.Begin);
    }
}

When ReadAsync return 0, it means TCP connection closing or closed. In MSDN:

The value of the TResult parameter contains the total number of bytes read into the buffer. The result value can be less than the number of bytes requested if the number of bytes currently available is less than the requested number, or it can be 0 (zero) if the end of the stream has been reached.

Share:
11,568
Philippe Paré
Author by

Philippe Paré

Software developer at Devolutions. Also working on a voxel based RPG. I Like regexes now, for some reason.

Updated on June 13, 2022

Comments

  • Philippe Paré
    Philippe Paré almost 2 years

    I recently started using the new C#5.0 "async" and "await" keywords. I thought I got the twist but realized one thing that made me doubt. Here's how I was asynchronously receiving data from a remote TcpClient. Once I accept the connection I call this function :

    static async void ReadAsync(TcpClient client)
    {
        NetworkStream ns = client.GetStream();
        MemoryStream ms = new MemoryStream();
        byte[] buffer = new byte[1024];
    
        while(client.Connected)
        {
            int bytesRead = await ns.ReadAsync(buffer, 0, buffer.Length);
            ms.Write(buffer, 0, bytesRead);
            if (!ns.DataAvailable)
            {
                HandleMessage(ms.ToArray());
                ms.Seek(0, SeekOrigin.Begin);
            }
        }
    }
    

    After data is received, the loop just goes on and on without reading anything. I tested this with a Console.WriteLine in the loop. Am I using it correctly? I feel I should not be using a while loop...