Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Core: TcpClient.GetStream crashes when using async

I tried to play with .NET Core and want to connect to a local TCP server. No issues when I do it synchronously (see first Connect method). When I try to do it with async/await (see second ConnectAsync method), it goes crazy and nearly undebuggable. I'm not sue if I use TcpClient correctly since there are not as many examples yet available on the web. The exact problems start after calling TcpClient.GetStream. I tried to debug into this with JustMyCode disabled and All exceptions checkbox in Visual Studio Code - but it just don't jumps into TcpClient.GetStream.

Observations in async mode:

  • sometimes it crashes in TcpClient.GetStream directly
  • sometimes it crashes after the the calling function returns (I saw the last Console.WriteLine appears in console sometimes)
  • the program immediately stops, debugger shuts down (no exception thrown)
  • return code is always zero (The program 'bla' has exited with code 0 (0x00000000))

My system/project setup:

  • Windows 10 64bit (Education)
  • .NET Core 1.0.0
  • Console application
  • local TCP Server, therefore no connectivity issues
  • Visual Studio Code (shouldn't matter)

Code:

public class Connection
{
    private TcpClient _client;
    public NetworkStream Stream { get; private set; }
    private CancellationTokenSource _token;

    public Connection()
    {
        _token = new CancellationTokenSource();
        _client = new TcpClient();
    }

    public void Connect(string host, int port)
    {
        Console.WriteLine("connecting...");
        _client.ConnectAsync(host, port);
        Console.WriteLine("connected!");

        while (!_client.Connected)
        {
            Thread.Sleep(20);
        }

        Console.WriteLine("getting stream...");
        Stream = _client.GetStream(); // works because of Thread.Sleep above until the socket is connected
        Console.WriteLine("got stream!");
    }

    public async Task ConnectAsync(string host, int port)
    {
        Console.WriteLine("connecting...");
        await _client.ConnectAsync(host, port);
        Console.WriteLine("connected!");

        // I know I could check for TcpClient.Connected but I see in debugger that the property is True

        Console.WriteLine("getting stream...");
        Stream = _client.GetStream(); // crash in GetStream / crash after this function has returned
        Console.WriteLine("got stream!"); // sometimes this is going to be printed, sometimes not
    }

    // ...
}
like image 285
The Wavelength Avatar asked Aug 26 '16 09:08

The Wavelength


1 Answers

The problem you are describing points to the main thread of your application dying. To identify that problem correctly one has to look at the entire applications and the threads that are active at any given moment.

But for example a simple console application terminates as soon as the main sub is terminated. Depending on how you call your ConnectAsync function you may lack something that ensures that the main loop is not terminated. Make sure that your main entry point is not a async function because this will terminate as soon as it reaches it's first await.

The main difference that happens between your two methods is that the ConnectAsync method actually switches threads very likely and executes the second part in a different thread, not blocking the thread it was called in like the Connect function does.

It explains exactly the behaviour your are describing. Some time after the

await _client.ConnectAsync(host, port);

line is executed the main loop of your application terminates and causes the entire .NET VM to shut down.

like image 82
Nitram Avatar answered Nov 15 '22 17:11

Nitram