Multi-Threaded TCP Server in C#

This tutorial introduces the concept of using threads to handle multiple clients in a TCP server. A TCP server is created and set to listen to a specific port. When a client is connected, a new thread is created that will handle the client’s communication.

The Client Class.

class ClientDemo
{
    private TcpClient _client;

    private StreamReader _sReader;
    private StreamWriter _sWriter;

    private Boolean _isConnected;

    public ClientDemo(String ipAddress, int portNum)
    {
        _client = new TcpClient();
        _client.Connect(ipAddress, portNum);

        HandleCommunication();
    }

    public void HandleCommunication()
    {
        _sReader = new StreamReader(_client.GetStream(), Encoding.ASCII);
        _sWriter = new StreamWriter(_client.GetStream(), Encoding.ASCII);

        _isConnected = true;
        String sData = null;
        while (_isConnected)
        {
            Console.Write("> ");
            sData = Console.ReadLine();

            // write data and make sure to flush, or the buffer will continue to 
            // grow, and your data might not be sent when you want it, and will
            // only be sent once the buffer is filled.
            _sWriter.WriteLine(sData);
            _sWriter.Flush();

            // if you want to receive anything
            // String sDataIncomming = _sReader.ReadLine();
        }
    }
}

In this class we’re going to need to a instantiate a TcpClient so we can have a connection with the server.

To handle communication to and from the server, a StreamReader and StreamWriter are used so we can easily write and read data. We could use a NetworkStream but you can’t force flush so I find it better to use the StreamReader/Writer.

To instantiate them you just have to feed them the stream from the client’s connection.

After that, I just ask for input and send it to the server. From there you can do anything you want. Process the data you receive from the server to close the client or do other fun stuff.

The Server Class

class TcpServer
{
    private TcpListener _server;
    private Boolean _isRunning;

    public TcpServer(int port)
    {
        _server = new TcpListener(IPAddress.Any, port);
        _server.Start();

        _isRunning = true;

        LoopClients();
    }

    public void LoopClients()
    {
        while (_isRunning)
        {
            // wait for client connection
            TcpClient newClient = _server.AcceptTcpClient();

            // client found.
            // create a thread to handle communication
            Thread t = new Thread(new ParameterizedThreadStart(HandleClient));
            t.Start(newClient);
        }
    }

    public void HandleClient(object obj)
    {
        // retrieve client from parameter passed to thread
        TcpClient client = (TcpClient)obj;

        // sets two streams
        StreamWriter sWriter = new StreamWriter(client.GetStream(), Encoding.ASCII);
        StreamReader sReader = new StreamReader(client.GetStream(), Encoding.ASCII);
        // you could use the NetworkStream to read and write, 
        // but there is no forcing flush, even when requested

        Boolean bClientConnected = true;
        String sData = null;

        while (bClientConnected)
        {
            // reads from stream
            sData = sReader.ReadLine();

            // shows content on the console.
            Console.WriteLine("Client > " + sData);

            // to write something back.
            // sWriter.WriteLine("Meaningfull things here");
            // sWriter.Flush();
        }
    }
}

In this class, you’ll have to have a TcpListener Class. When you start your Server class, you’ll be opening a port on the machine and will be waiting for clients to connect.

Once a client connects, a thread is fired and the client who got connected is passed to the thread as a parameter, so we don’t loose the connection.

The thread starts a function that will handle communication with clients. First, we recover the client from the object passed in the thread as parameter. Then we create our streams to write and read from the client’s stream. Each client has a two private streams, that is why they are created inside HandleClient(object obj) method, so they don’t share the same streams.

After that, you can do what you want, send and receive data :)

Client Main Class

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Multi-Threaded TCP Server Demo");
            Console.WriteLine("Provide IP:");
            String ip = Console.ReadLine();

            Console.WriteLine("Provide Port:");
            int port = Int32.Parse(Console.ReadLine());

            ClientDemo client = new ClientDemo(ip, port);
        }
    }
}

Server Main Class

namespace Multi_Threaded_TCP
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Multi-Threaded TCP Server Demo");
            TcpServer server = new TcpServer(5555);
        }
    }
}

Note: Just change the “5555” to whatever you want. That’s the port the server will be listening to. Or even better, ask for it when launching the application or store it in a configuration file. ;)

Note: This is far from a optimal solution and shouldn’t be used in real life applications. This tutorial only introduces some concepts, namely, Threads, TCP listeners and TCP Clients. You should know that each thread created will use 1Mb of memory, so its easy to see where this approach is not good. If lots of client connections come in, you’ll quickly see the memory ramp up. A better way to manage this would be to create a limited amount of threads, and set the clients on queues, re-using threads as the jobs finish, and so on. A new, better way of creating a Multi-Threaded Server would be using Task, from the Task Parallel Library, but I’ll talk more on that later. :)