Search code examples
c#async-awaittcplistener

ObjectDisposedException on AcceptTcpClientAsync() for new TcpListener instance


I am stuck on a problem with the TcpListener class, after stopping the server and trying to start it again. What I am basically trying to do is to use the AcceptTcpClientAsync() method to process incoming connection requests and provide the possibility to restart the server.

Minimal Example:

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();
        }
    }
}

On the second call to await listener.AcceptTcpClientAsync() I am receiving an ObjectDisposedException for a socket.

Any idea or input how to overcome this problem?

Thanks!


Solution

  • Seems to be an unhealthy combination of static variables and async void. After doing some re-write to remove the static variable and use a factory method that returns the listener, the exception still occurs. But now I got it in the await call of the corresponding instance where Stop() has been called. This makes sense, cause the accept call has to return after stop, but it must signal that no client is available (which it does by throwing the exception).

    So avoid async void, especially in combination with static members. Seems to be really toxic and sorry that I don't have any deeper explanation (except the link).

    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);
            }
        }
    }