新TcpListener实例的AcceptTcpClientAsync()上的ObjectDisposedException

时间:2018-12-10 08:48:22

标签: c# async-await tcplistener

在停止服务器并尝试再次启动它之后,我陷入了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的套接字。

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

谢谢!

1 个答案:

答案 0 :(得分:2)

似乎是静态变量和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);
        }
    }
}