Search code examples
c#.netmultithreadingtcp

Is BeginAcceptTcpClient thread safe? C#


I´m starting in the world of TCP Asynchronous servers, searching a way to handle several connections at the same time I found out that BeginAcceptTcpClient could be a solution.

I´ve found two possible ways to use BeginAcceptTcpClient at the start of the server to receive connections. My question would be: what´s the difference between those two and which one would be thread safe (or if both are).

FIRST WAY

Calling BeginAcceptTcpClient inside the callback.

static TcpListener socket = new TcpListener(IPAddress.Any, 4444);

public static void InitNetwork()
        {
            socket.Start();
            socket.BeginAcceptTcpClient(new AsyncCallback(OnClientConnect), null);
        }

private static void OnClientConnect(IAsyncResult ar)
        {
            TcpClient newclient = socket.EndAcceptTcpClient(ar);
            socket.BeginAcceptTcpClient(new AsyncCallback (OnClientConnect), null); // Call the Callback again to continue listening

            HandleClient.CreateConnection(newclient); //Do stuff with the client recieved
        }

SECOND WAY

Using AutoResetEvent.

static TcpListener socket = new TcpListener(IPAddress.Any, 4444);
private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false);

public static void InitNetwork()
        {
            socket.Start();

            while(true)
            {
              socket.BeginAcceptTcpClient(new AsyncCallback(OnClientConnect), null);
              connectionWaitHandle.WaitOne(); // Wait until a client has begun handling an event
              connectionWaitHandle.Reset(); // Reset wait handle or the loop goes as fast as it can (after first request)
            }

        }

private static void OnClientConnect(IAsyncResult ar)
        {
            TcpClient newclient = socket.EndAcceptTcpClient(ar);
            connectionWaitHandle.Set(); //Inform the main thread this connection is now handled

            HandleClient.CreateConnection(newclient);  //Do stuff with the client recieved
        }

I´m searching the correct way to handle multiple connections (been thread safe). I appreciate any answer.


Solution

  • I prefer AcceptTcpClientAsync. It's simpler than BeginAcceptTcpClient and still asynchronous.

    public async Task InitNetwork()
    {
        while( true )
        {
            TcpClient newclient = await socket.AcceptTcpClientAsync();
            Task.Run( () => HandleClient.CreateConnection( newclient ) );
        }
    }
    

    Internally, AcceptTcpClientAsync use Task.Factory.FromAsync to wrap BeginAcceptTcpClient and EndAcceptTcpClient into a Task object.

    public Task<TcpClient> AcceptTcpClientAsync()
    {
        return Task<TcpClient>.Factory.FromAsync(BeginAcceptTcpClient, EndAcceptTcpClient, null);
    }