.NET Core:使用异步时TcpClient.GetStream崩溃

时间:2016-08-26 09:24:49

标签: c# windows sockets async-await .net-core

我尝试使用.NET Core并希望连接到本地TCP服务器。我同步执行时没有问题(请参阅第一个Connect方法)。当我尝试使用async / await(请参阅第二个ConnectAsync方法)时,它会变得疯狂并几乎无法辨认。如果我正确使用TcpClient,我不会起诉,因为网上还没有那么多的例子。调用TcpClient.GetStream后,确切的问题就开始了。我试图通过Visual Studio Code中的JustMyCode禁用和All exceptions复选框调试此功能 - 但它不会跳转到TcpClient.GetStream

async模式下的观察:

  • 有时会直接在TcpClient.GetStream崩溃
  • 有时它会在调用函数返回后崩溃(我看到有时会在控制台中显示最后一个Console.WriteLine
  • 程序立即停止,调试器关闭(没有异常抛出)
  • 返回代码始终为零(The program 'bla' has exited with code 0 (0x00000000)

我的系统/项目设置:

  • Windows 10 64bit(教育)
  • .NET Core 1.0.0
  • 控制台应用程序
  • 本地TCP服务器,因此没有连接问题
  • Visual Studio代码(不应该)

代码:

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
    }

    // ...
}

1 个答案:

答案 0 :(得分:5)

您所描述的问题指向应用程序死亡的主线程。要正确识别该问题,必须查看整个应用程序以及在任何给定时刻处于活动状态的线程。

但是,例如,一个简单的控制台应用程序会在主要子终止后立即终止。根据您调用ConnectAsync函数的方式,您可能缺少确保主循环不会终止的内容。确保您的主要入口点不是async函数,因为它会在它到达第一个await后立即终止。

两种方法之间发生的主要区别是ConnectAsync方法实际上很可能切换线程,并在另一个线程中执行第二部分,而不是像{{1}那样阻塞它所调用的线程功能确实。

它准确地解释了您所描述的行为。

之后的一段时间
Connect
执行

行后,应用程序的主循环终止并导致整个.NET VM关闭。