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

The*_*gth 9 c# sockets windows 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
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

Nit*_*ram 6

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

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

两种方法之间发生的主要区别在于该ConnectAsync方法实际上非常可能地切换线程并在不同的线程中执行第二部分,而不像Connect函数那样阻塞它被调用的线程.

它准确地解释了您描述的行为.一段时间之后

await _client.ConnectAsync(host, port);
Run Code Online (Sandbox Code Playgroud)

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