tcplistener/tcpclient await is stopping code after from running

56 views Asked by At

This code outputs "8096" 13 times as expected (ceil(100,000/8096) = 13)

But then after the while loops in both functions nothing else runs but program finishes, the 2 console.writlelines after them don't get run (does work printing before, just not after the while loop)

Here is my code:

Tcpclient function:

public static async void Main()
{       
    using TcpClient client = new TcpClient("localhost",50000);
    using NetworkStream stream = client.GetStream();
    byte[] data = RandomNumberGenerator.GetBytes(100000);
    await stream.WriteAsync(data,0,data.Length);
    byte[] bytes = new byte[8096];
    int i;
    while((i = await stream.ReadAsync(bytes, 0, bytes.Length))>0)
    {
        Console.WriteLine(i);
    }
    Console.WriteLine("this doesnt get printed");
    client.Close();
    return;
}

tcplistener function:

public static async void Main()
{               
    try
    {   
        TcpListener server = new TcpListener(IPAddress.Any,50000);
        server.Start();
        using TcpClient client = await server.AcceptTcpClientAsync();
        using NetworkStream stream = client.GetStream();
        byte[] bytes = new byte[8096];
        byte[] return_bytes = new byte[8096];
        int i;
        while((i = await stream.ReadAsync(bytes, 0, bytes.Length))>0)
        {
            await stream.WriteAsync(return_bytes,0,return_bytes.Length);
        }
        Console.WriteLine("this doesn't get printed");
        client.Close();
        server.Stop();
    }
    catch(Exception ex)
    {
        Console.WriteLine("port already in use");
    }
}

Tried making it synchronous and putting them in threads but that didn't work

2

There are 2 answers

1
Charlieface On

You need to hand off the reading to another task or thread, as otherwise the client is blocked waiting for the listener, which in turn is blocked waiting to echo to the client, which is still blocked trying to send.

public static async Task Main()
{       
    byte[] data = RandomNumberGenerator.GetBytes(100000);
    using TcpClient client = new TcpClient();
    await client.ConnectAsync("localhost", 50000);  // connect asynchronously
    using NetworkStream stream = client.GetStream();   // needs using
    var task = Task.Run(async () => {      // hand off reads
        byte[] bytes = new byte[8096];
        int i;
        while((i = await stream.ReadAsync(bytes, 0, bytes.Length)) > 0)
        {
            Console.WriteLine(i);
        }
    });
    await stream.WriteAsync(data, 0, data.Length);
    await task;  // wait for reads to finish
    Console.WriteLine("this doesnt get printed");
}

See also @StephenCleary's blog for more.

0
Rowan Smith On

Your code is working correctly. You send 100000 bytes and receive 100000 bytes echo'd back to you.

You then sit waiting for the server to send more data, but the server will only send more data if it receives data.

So the client will await forever waiting for the server to send it some data. The server will await for ever waiting for the client to send it some data.

If you want the program to continue or exit, then you need to either send more data or exit the loop after you have processed the 100000 bytes.