Skip to main content

This post is part of a series, to see the other posts in the series go to the series index.

imageWriting a TCP server is something that modern business .NET developers do not need to worry about, we have WCF which has abstracted us from understanding TCP servers & clients for business apps – but for some systems we still need to write a TCP server or client.

Microsoft has optimised the .NET framework for common scenarios – for example doing something like SMTP where a server where it is always running and clients connect when they have data, provide the data and disconnect. So what you may do is start a server (in it’s own thread so you can still do other things in the app), and wait for client connections. At this point you are blocking processing until a client connects. When a client connects, you get the data and process it (in a new thread, so you can allow more clients to connect).

The advantage of this is this is a simple model and is fairly easy to setup, but there is a few problems with this:

  1. You have this blocking point while you wait for clients, so trying to shut it down is difficult. As the view of a server is that it should always be up, this is not an optimised path so there is no way. Basically you will need to deal with task manager to kill the process.
  2. You have lots of threading and you must handle threads. Threads are hard to understand and easy to fail so we are opening up potential for problems.
  3. You assume the client will connect and send data at once and will go away. Once again this is the “normal” scenario (think HTTP or SMTP) but there are scenarios where this is not possible.

Below is the sample to do this in a console application.

class Program
{
    private const int BufferSize = 4096;
    private static bool ServerRunning = true;

    static void Main(string[] args)
    {
        new Thread(RunTCPServer).Start();
        Console.WriteLine("Press enter to shutdown");
        Console.ReadLine();
        ServerRunning = false;
    }

    private static void RunTCPServer()
    {
        var tcpServer = new TcpListener(IPAddress.Any, 9000);
        try
        {
            tcpServer.Start();
            while (ServerRunning)
            {
                var tcpClientConnection = tcpServer.AcceptTcpClient();
                Console.WriteLine("Client connection");

                // spawn thread to deal with it     
                new Thread(ClientConnection).Start(tcpClientConnection);
            }
        }
        finally
        {
            tcpServer.Stop();
        }
    }

    private static void ClientConnection(object state)
    {
        var tcpClientConnection = state as TcpClient;
        var stream = tcpClientConnection.GetStream();
        var buffer = new byte[BufferSize];

        var amountRead = stream.Read(buffer, 0, BufferSize);
        var message = Encoding.ASCII.GetString(buffer, 0, amountRead);
        Console.WriteLine("Client sent: {0}", message);
    }
}