TCP servers with .NET: Scenario 4 & Non-blocking servers with .NET 4.5

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

image Scenario 3 is a great solution to the problem, but the issue was that its complexity far exceeded that of scenario 1 or scenario 2. We were calling other methods, using recursive-like behaviors, and all sorts of non-obvious things that were difficult to grasp.

Fortunately, Microsoft addressed this issue, and with .NET 4.5, we gained some help through its new async features, particularly the _async_ and _await_ keywords.

In short, async informs the compiler that a method will spawn an asynchronous process and will return to the caller at some point, while await designates the point in the code where execution pauses asynchronously.

Using these, I was able to modify the code to closely resemble the structure of scenario 1 (including the Boolean continueRunningServer flag). However, the two methods are enhanced with the async keyword and use await with _AcceptTcpClientAsync_ and _ReadAsync_—new methods in the TCP stack that return Task<T>, a fundamental requirement for async calls.

I think this is a fantastic improvement, and I cannot wait for .NET 4.5 to ship! 😊

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

    static void Main(string[] args)
    {
        var tcpServer = new TcpListener(IPAddress.Any, 9000);
        try
        {
            tcpServer.Start();

            ListenForClients(tcpServer);

            Console.WriteLine("Press <kbd>Enter</kbd> to shut down");
            Console.ReadLine();
        }
        finally
        {
            tcpServer.Stop();
        }
    }

    private static async void ListenForClients(TcpListener tcpServer)
    {
        while (ServerRunning)
        {
            var tcpClient = await tcpServer.AcceptTcpClientAsync();
            Console.WriteLine("Connected");
            ProcessClient(tcpClient);
        }
    }

    private static async void ProcessClient(TcpClient tcpClient)
    {
        while (ServerRunning)
        {
            var stream = tcpClient.GetStream();
            var buffer = new byte[BufferSize];
            var amountRead = await stream.ReadAsync(buffer, 0, BufferSize);

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