DEV Community

Cover image for .NET TCPListener: Accepting Multiple Client Connections
Nick Proud
Nick Proud

Posted on

.NET TCPListener: Accepting Multiple Client Connections

TCP. It's a key component of the foundation of the internet. We take it for granted every day while we're online. Sometimes, it becomes necessary to leverage this amazing protocol to implement reliable and fast communication. Here's a brief explanation of how I used the .NET framework's TCPListener to create a simple TCP server in the form of Easy-TCP-Server, a .NET core library which handles incoming TCP data from multiple clients via 'channels' of connections between the clients and the server.

The Use Case

The solution is built in order to allow the project which references it to quickly spin up a TCP server which can then listen for any incoming TCP traffic. The aim is to make it easy to create an endpoint that any client can send TCP requests to and receive responses from on a persistent, managed connection. (If needed.) This may be useful for many different reasons, with examples like using remote clients to trigger the execution of a remote process, or sending data to a server for persistence in a database to name just a few.

I'll go into more detail about the overall development of the project in another post at some point, but for now, I want to explain how I was able to accept multiple connections on a .NET TCPListener.

Accepting multiple clients

The documentation's main example for TCPListener demonstrates how to listen for a request, receive and receive it on the same thread. For our use case, we want to be able to receive any incoming request and then handle it on a separate thread, to prevent our listener from blocking.

First of all, let's initialize a TCPListener

Listener = new TcpListener(IPAddress.Parse("127.0.0.1!), 12400); Listener.Start();
Enter fullscreen mode Exit fullscreen mode

Here we create a listener which will be listening on the localhost, on port 12400, before starting it.

Now we need to start the listener and create a loop that while running, accepts incoming TCP clients before we do something with the incoming request. .NET presents a couple of options for receiving TCPClient connections within the TCPListener class, with the main one being AcceptTcpClient(). This will allow us to listen out for incoming requests on our specified hostname and port, and would be fine if we wanted to block the current thread in order to handle the traffic, like below:

while (true) { var client = await Listener.AcceptTcpClient(); //Do Something }
Enter fullscreen mode Exit fullscreen mode

But we don't want to block. We want to accept requests asynchronously so that on each request, we can make a different thread for handling the incoming traffic. To achieve this, we can still use a while loop, but instead of using AcceptTcpClient() let's use AcceptTcpClientAsync(). Using this method, the thread will no longer be blocked, as we are awaiting any incoming requests. When a request is received, we can fire off our handler logic in the form of a Task, so that we are not blocking the program further. This will allow multiple clients to hit our listener and be handled.

while (true) { var client = await Listener.AcceptTcpClientAsync(); await Task.Run(() => //Do Something ); }
Enter fullscreen mode Exit fullscreen mode

Here is a more detailed example of the implementation

public class Server 
{ 
    bool _running; 
    public bool Running 
    { 
        get 
        { 
           return _running; 
        } 
        set 
        { 
            _running = value; 
        } 
     } 
    public Server() 
    { 
        Listener = new TcpListener("127.0.0.1", 12400); 
    } 
    public async void Start() 
    { 
        try 
        {
            Listener.Start(); Running = true; 
            while (Running)  
            { 
                 var client = await Listener.AcceptTcpClientAsync();        
                 await Task.Run(() => //Do something); 
             } 
          } 
          catch(SocketException) 
          {  
              throw; 
          }  
     } 
    public void Stop() 
    { 
        Listener.Stop(); 
        Running = false; 
     } 
}
Enter fullscreen mode Exit fullscreen mode

Here, I've provided a means to start the listener's accept loop and a means to gracefully close it. I've also added a handler for any SocketExceptions that may be thrown.

There it is. A simple TCPListener that can accept multiple connections and handle them on a separate thread. This is a more simplified version of the server I wrote for the Easy-TCP-Server library, the source of which is available for your use here.

Top comments (1)

Collapse
 
legistek profile image
Peter Moore

Why would you await the Task.Run? Wouldn't that still block the loop from iterating to the next call to AcceptTcpClientAsync?