10 August 2018

.NET - HTTP server with TcpListener

It's easy to create a little web server using HttpListener, but it must run as administrator to listen to anything but the localhost. It can also be done with TcpListener, but it's somewhat trickier. The firewall will prompt to allow network access though, which the HttpListener won't, because it uses HTTP.SYS that listens on behalf of the application.

HttpServer class

private TcpListener Listener { get; set; }

public void Listen()
{
    Listener = new TcpListener(IPAddress.Any, 2000);
    Listener.Start();

    while (true)
    {
       var client = Listener.AcceptTcpClient();
       ThreadPool.QueueUserWorkItem((state) => Handle(client)); //Handle each request on it's own thread.
    }
}

private void Handle(TcpClient client)
{
    using (var io = client.GetStream())
    using (var reader = new StreamReader(io))
    using (var writer = new StreamWriter(io))
    {
        //Request
        string[] line = reader.ReadLine()?.Split(); //Do not read to end! It would hang.
        string method = line[0]; //GET, POST, ...
        string url = line[1]; //The requested URL.

        //Response
        string content = "<html><body>EGS</body></html>";
        writer.WriteLine("HTTP/1.1 200 OK");
        writer.WriteLine("Content-Type: text/html; charset=UTF-8");
        writer.WriteLine($"Content-Length: {content.Length}");
        writer.WriteLine("Connection: close");
        writer.WriteLine();
        writer.WriteLine(content);
    }

    client.Close();
}

Start the server

Server = new HttpServer();
new Thread(new ThreadStart(Server.Listen)).Start(); //On a separate thread, so the UI doesn't hang.