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

9
我尝试使用.NET Core并连接到本地TCP服务器。当我同步执行时没有问题 (请参见第一个Connect方法)。但是,当我尝试使用async/await执行时(请参见第二个ConnectAsync方法),它变得非常混乱,几乎无法调试。我不确定是否正确使用TcpClient,因为网络上还没有太多的示例。确切的问题在调用TcpClient.GetStream后开始。我尝试禁用JustMyCode并勾选Visual Studio Code中的All exceptions复选框进行调试,但是它不进入TcpClient.GetStream

async模式下的观察结果:

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

我的系统/项目设置:

  • Windows 10 64位(Education)
  • .NET Core 1.0.0
  • 控制台应用程序
  • 本地TCP服务器,因此没有连接问题
  • Visual Studio 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
    }

    // ...
}

我对非异步版本的connect感到困惑...连接后,睡眠,现在尝试获取流.. 在第二个版本中你不需要这样做.. 你只需连接并期望获得流.. - BugFinder
在同一实例上,您只调用一次还是多次调用ConnectAsync? - Guillaume
2
你尝试获取抛出的异常了吗?也许这会给出一些提示。如果你能分享一下就好了。 - Nitram
@BugFinder,是的,如上所述,我确定我已连接,因为我使用调试器查看了属性。 - The Wavelength
@TheWavelength 这正是我所需要的细节。现在正在撰写一个回答。 - Nitram
显示剩余2条评论
1个回答

6
您所描述的问题指向了应用程序的主线程死亡。要正确识别该问题,必须查看整个应用程序以及在任何给定时刻处于活动状态的线程。
例如,简单的控制台应用程序会在主子程序终止时立即终止。根据您如何调用ConnectAsync函数,您可能缺少确保主循环不终止的某些内容。请确保您的主入口点不是一个async函数,因为一旦它达到第一个await就会终止。
两种方法之间发生的主要区别是ConnectAsync方法实际上非常可能切换线程,并在不阻塞调用它的线程的情况下在不同的线程中执行第二部分,而Connect函数则不同。
这解释了您所描述的行为。在一段时间之后,问题可能会出现。
await _client.ConnectAsync(host, port);

当执行该行时,应用程序的主循环将终止并导致整个.NET虚拟机关闭。


非常感谢!即使不知道我如何调用“ConnectAsync”,您也能够解决问题。解决方案就是让入口点等待调用“ConnectAsync”的函数调用结果。 - The Wavelength

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接