The Wavelength The Wavelength - 3 months ago 41
C# Question

.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
}

// ...
}

Answer

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.

Comments