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

.NET Core: TcpClient.GetStream crashes when using async

我尝试使用 .NET Core 并想连接到本地 TCP 服务器。当我同步执行时没有问题(请参阅第一个 Connect 方法)。当我尝试使用 async/await(参见第二个 ConnectAsync 方法)时,它变得疯狂并且几乎无法调试。如果我正确使用 TcpClient,我不会起诉,因为网络上还没有那么多示例。确切的问题在调用 TcpClient.GetStream 之后开始。我尝试在 Visual Studio 代码中禁用 JustMyCodeAll exceptions 复选框进行调试 - 但它不会跳入 TcpClient.GetStream.

async 模式下的观察:

我的 system/project 设置:

代码:

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
    }

    // ...
}

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

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

时立即终止

这两种方法之间的主要区别在于 ConnectAsync 方法实际上很可能会切换线程并在不同的线程中执行第二部分,而不是像 [= 那样阻塞调用它的线程15=] 功能确实如此。

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

之后的一段时间
await _client.ConnectAsync(host, port);

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