【问题标题】:ObjectDisposedException on AcceptTcpClientAsync() for new TcpListener instance新 TcpListener 实例的 AcceptTcpClientAsync() 上的 ObjectDisposedException
【发布时间】:2019-05-11 03:29:43
【问题描述】:

在停止服务器并尝试重新启动后,我遇到了 TcpListener 类的问题。我基本上想做的是使用AcceptTcpClientAsync() 方法来处理传入的连接请求并提供重新启动服务器的可能性。

小例子:

class Program
{
    private static TcpListener listener;

    static void Main(string[] args)
    {
        StartServerAsync();

        StopServer();

        StartServerAsync();

        Console.ReadKey();
    }

    private static void StopServer()
    {
        if (listener != null)
            listener.Stop();
    }

    private async static void StartServerAsync() 
    {
        listener = new TcpListener(IPAddress.Loopback, 1234);
        listener.Start();

        while (true)
        {
            var client = await listener.AcceptTcpClientAsync();
        }
    }
}

在第二次调用await listener.AcceptTcpClientAsync() 时,我收到了ObjectDisposedException 的套接字。

任何想法或意见如何克服这个问题?

谢谢!

【问题讨论】:

  • 那是你的完整代码还是清理后的版本?您是否在循环中的某处执行“listener.Close()”?
  • @AnuViswan 这是完整的代码,我试图找出这个简化代码的问题
  • 恕我直言,这是一个清理版本。然而,它抛出了所描述的异常。我的猜测是,它会在第一次调用停止之后执行此操作。但实际上它在第二个实例的最后一次等待调用中抛出。我也稍微改写了一下,并为每个实例使用了不同的端口(不是地址),但错误仍然存​​在。

标签: c# async-await tcplistener


【解决方案1】:

似乎是静态变量和async void 的不健康组合。在进行了一些重写以删除静态变量并使用返回侦听器的工厂方法后,异常仍然发生。但是现在我在调用 Stop() 的相应实例的 await 调用中得到了它。这是有道理的,因为接受调用必须在停止后返回,但它必须表明没有可用的客户端(它通过抛出异常来实现)。

所以avoid async void,尤其是与静态成员结合使用。似乎真的很有毒,很抱歉我没有更深入的解释(除了链接)。

private static void Main(string[] args)
{
    var listener1 = StartServerAsync(1234).Result;
    StopServer(listener1);
    var listener2 = StartServerAsync(1235).Result;
    StopServer(listener2);
    var listener3 = StartServerAsync(1236).Result;
    StopServer(listener3);

    Console.ReadKey();
}

private static void StopServer(TcpListener listener)
{
    if (listener != null)
    {
        Console.WriteLine("Stop on port "+ listener.LocalEndpoint);
        listener.Stop();
        listener = null;
    }
}

private static async Task<TcpListener> StartServerAsync(int port)
{
    var listener = new TcpListener(IPAddress.Loopback, port);
    listener.Start();
    Console.WriteLine("Started on port " + port);

    var task = Task.Run(async () => await WaitForConnection(listener));
    await Task.Delay(100);

    return listener;
}

private static async Task WaitForConnection(TcpListener listener)
{
    while (true)
    {
        try
        {
            var client = await listener.AcceptTcpClientAsync();
        }
        catch (ObjectDisposedException)
        {
            Console.WriteLine("Failed on " + listener.LocalEndpoint);
        }
    }
}

【讨论】:

  • 您的回答让我找到了正确的方向。在实际代码中,我没有使用任何静态变量,但是停止和(重新)启动服务器的调用是从处理连接接受的同一线程进行的。谢谢!
猜你喜欢
  • 1970-01-01
  • 2013-10-13
  • 1970-01-01
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-05
  • 1970-01-01
相关资源
最近更新 更多