Skip to main content

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

imageIn the previous post we looked at the simplest of all TCP server scenarios, but what about the third issue highlighted in the post: It assumes your clients will connect, pass data and disconnect. What about for clients the connect optimistically so that they can send data at some point in the future?

This is very common for games, where the client connection process is very slow or where even smallest of overhead should be eliminated.

In this mode rather than read data and disconnect we add a loop on the reading and read until we get a end of message notice and will then end the connection.

The problem with extending the simple model to this, is that we now have a blocking action, i.e. code can not continue until something happens, in both the server thread and in all the client connection threads. So now shutting down the server is not just related to the server, we need clients to disconnect properly first.

What is common here, is to send a message to all clients saying it will shutdown and then having them do that. That assumes we have pretty smart clients and/or control them and in scenarios you do not control the TCP clients it could be a bit problem. We will look at a way to solve this in the next post, but for now the code below shows how this is done, and compared to scenario 1 it contains one small change:

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];
        while (ServerRunning)  // new in scenario 2
        {
            var amountRead = stream.Read(buffer, 0, BufferSize);
            var message = Encoding.ASCII.GetString(buffer, 0, amountRead);
            Console.WriteLine("Client sent: {0}", message);
        }
    }
}