Click here to Skip to main content
13,256,123 members (26,711 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


224 bookmarked
Posted 3 Sep 2012

Build Your Own Web Server

, 9 Oct 2012
Rate this:
Please Sign up or sign in to vote.
Let's build a simple web server and make it accessible from the internet.



We will learn to write a simple web server which can send responses to the most well-known HTTP methods (GET and POST), in C#. Then we will make this server accessible from the internet. This time we will really say "Hello world!"

Simple Web Server


HTTP Protocol

HTTP is a communication protocol between servers and clients. It uses TCP/IP protocol to send/receive requests/responses.

There are a few HTTP methods and we will implement two of them; GET and POST.


What happens when we write an address into address bar of our web browser and hit enter? (We mostly don't specify a port number although it is required for TCP/IP, because it has a default value for http and it is 80. We don't have to specify it if it is 80.)

GET / HTTP/1.1\r\n
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:14.0) Gecko/20100101 Firefox/14.0.1\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: tr-tr,tr;q=0.8,en-us;q=0.5,en;q=0.3\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: keep-alive\r\n\r\n

This is the GET request which is sent by our browser to the server using TCP/IP. This means the browser requests the server to send the contents of "/" from the root folder of "".

We (or browsers) can add more headers. But the most simplified version of this request is below:

GET / HTTP/1.1\r\n


POST requests are similar to GET requests. In a GET request, variables are appended to the urls using ? character. But in a POST request, variables are appended to the end of the request after 2 line break characters and total length (content-length) is specified. 

POST /index.html HTTP/1.1\r\n
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20100101 Firefox/15.0.1\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: tr-tr,tr;q=0.8,en-us;q=0.5,en;q=0.3\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: keep-alive\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 35\r\n\r\n

Simplified version of this request:

POST /index.html HTTP/1.1\r\n
Content-Length: 35\r\n\r\n


When a request is received by the server it is parsed and a response with a status code is returned:  

HTTP/1.1 200 OK\r\n
Server: Apache/ (Unix) (Red-Hat/Linux)\r\n
Content-Length: {content_length}\r\n
Connection: close\r\n
Content-Type: text/html; charset=UTF-8\r\n\r\n
the content of which length is equal to {content_length}

This is the response header. "200 OK" means everything is OK, requested content will be returned. There are many status codes. We will use just 200, 501 and 404: 

  • "501 Not Implemented": Method is not implemented. We will implement only GET and POST. So, we will send response with this code for all other methods.
  • "404 Not Found": Requested content is not found.

Content Types

Servers must specify the type of the content in their response. There are many content types and these are also called "MIME (Multipurpose Internet Mail Extensions) types" (because they are also used to identify non-ASCII parts of emails). Here are the content types that we will use in our implementation: (you can modify the code and add more) 

  • text/html
  • text/xml
  • text/plain
  • text/css
  • image/png
  • image/gif
  • image/jpg
  • image/jpeg
  • application/zip

If servers specify the wrong content types contents will be misinterpreted. For example, if a server sends plain text using the "image/png" type, the client tries to show the text as an image.


If we want our server to be available even if a response is being sent to an another client at that time, we must create new threads for every request. Thus, every thread handles a single request and exits after it completes its mission. (Multithreading also speeds up page loadings, because if we request a page that uses CSS and includes images, different GET requests are sent for every image and CSS file.)

Implementation of a Simple Web Server

Now we are ready to implement a simple web server. First of all, let's define variables that we will use:

public bool running = false; // Is it running?

private int timeout = 8; // Time limit for data transfers.
private Encoding charEncoder = Encoding.UTF8; // To encode string
private Socket serverSocket; // Our server socket
private string contentPath; // Root path of our contents

// Content types that are supported by our server
// You can add more...
// To see other types:
private Dictionary<string, string> extensions = new Dictionary<string, string>()
    //{ "extension", "content type" }
    { "htm", "text/html" },
    { "html", "text/html" },
    { "xml", "text/xml" },
    { "txt", "text/plain" },
    { "css", "text/css" },
    { "png", "image/png" },
    { "gif", "image/gif" },
    { "jpg", "image/jpg" },
    { "jpeg", "image/jpeg" },
    { "zip", "application/zip"}

Method to start our server: 

public bool start(IPAddress ipAddress, int port, int maxNOfCon, string contentPath)
    if (running) return false; // If it is already running, exit.

        // A tcp/ip socket (ipv4)
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
        serverSocket.Bind(new IPEndPoint(ipAddress, port));
        serverSocket.ReceiveTimeout = timeout;
        serverSocket.SendTimeout = timeout;
        running = true;
        this.contentPath = contentPath;
    catch { return false; }

    // Our thread that will listen connection requests
    // and create new threads to handle them.
    Thread requestListenerT = new Thread(() =>
        while (running)
            Socket clientSocket;
                clientSocket = serverSocket.Accept();
                // Create new thread to handle the request and continue to listen the socket.
                Thread requestHandler = new Thread(() =>
                    clientSocket.ReceiveTimeout = timeout;
                    clientSocket.SendTimeout = timeout;
                    try { handleTheRequest(clientSocket); }
                        try { clientSocket.Close(); } catch { }

    return true;

Method to stop the server:

public void stop()
    if (running)
        running = false;
        try { serverSocket.Close(); }
        catch { }
        serverSocket = null;

The most important part of the code:

private void handleTheRequest(Socket clientSocket)
    byte[] buffer = new byte[10240]; // 10 kb, just in case
    int receivedBCount = clientSocket.Receive(buffer); // Receive the request
    string strReceived = charEncoder.GetString(buffer, 0, receivedBCount);

    // Parse method of the request
    string httpMethod = strReceived.Substring(0, strReceived.IndexOf(" "));

    int start = strReceived.IndexOf(httpMethod) + httpMethod.Length + 1;
    int length = strReceived.LastIndexOf("HTTP") - start - 1;
    string requestedUrl = strReceived.Substring(start, length);

    string requestedFile;
    if (httpMethod.Equals("GET") || httpMethod.Equals("POST"))
        requestedFile = requestedUrl.Split('?')[0];
    else // You can implement other methods...

    requestedFile = requestedFile.Replace("/", @"\").Replace("\\..", "");
    start = requestedFile.LastIndexOf('.') + 1;
    if (start > 0)
        length = requestedFile.Length - start;
        string extension = requestedFile.Substring(start, length);
        if (extensions.ContainsKey(extension)) // Do we support this extension?
            if (File.Exists(contentPath + requestedFile)) //If yes check existence of the file
                // Everything is OK, send requested file with correct content type:
                  File.ReadAllBytes(contentPath + requestedFile), extensions[extension]);
                notFound(clientSocket); // We don't support this extension.
                                        // We are assuming that it doesn't exist.
        // If file is not specified try to send index.htm or index.html
        // You can add more (default.htm, default.html)
        if (requestedFile.Substring(length - 1, 1) != @"\")
            requestedFile += @"\";
        if (File.Exists(contentPath + requestedFile + "index.htm"))
              File.ReadAllBytes(contentPath + requestedFile + "\\index.htm"), "text/html");
        else if (File.Exists(contentPath + requestedFile + "index.html"))
              File.ReadAllBytes(contentPath + requestedFile + "\\index.html"), "text/html");

Responses for different status codes:

private void notImplemented(Socket clientSocket)
    sendResponse(clientSocket, "<html><head><meta 
        http-equiv=\"Content-Type\" content=\"text/html; 
        </head><body><h2>Atasoy Simple Web 
        Server</h2><div>501 - Method Not 
        "501 Not Implemented", "text/html");


private void notFound(Socket clientSocket)
    sendResponse(clientSocket, "<html><head><meta 
        http-equiv=\"Content-Type\" content=\"text/html; 
        charset=utf-8\"></head><body><h2>Atasoy Simple Web 
        Server</h2><div>404 - Not 
        "404 Not Found", "text/html");

private void sendOkResponse(Socket clientSocket, byte[] bContent, string contentType)
    sendResponse(clientSocket, bContent, "200 OK", contentType);

The method that will send responses to clients:

// For strings
private void sendResponse(Socket clientSocket, string strContent, string responseCode,
                          string contentType)
    byte[] bContent = charEncoder.GetBytes(strContent);
    sendResponse(clientSocket, bContent, responseCode, contentType);

// For byte arrays
private void sendResponse(Socket clientSocket, byte[] bContent, string responseCode,
                          string contentType)
        byte[] bHeader = charEncoder.GetBytes(
                            "HTTP/1.1 " + responseCode + "\r\n"
                          + "Server: Atasoy Simple Web Server\r\n"
                          + "Content-Length: " + bContent.Length.ToString() + "\r\n"
                          + "Connection: close\r\n"
                          + "Content-Type: " + contentType + "\r\n\r\n");
    catch { }


// to create new one:
Server server = new Server();
// to start it
server.start(ipAddress, port, maxconnections, contentpath);
// to stop it

Let's Say "Hello" to All The World!

Our simple web server is ready. Now we will make it accessible from the internet. To achieve this, we must redirect requests that come to our modem to our computer. It is simple if our modem supports UPnP.

  1. Download this UPnP Port Forwarder and run it.
  2. Click "Search For Devices" button. If your modem supports UPnP, it will be added to the combobox. 
  3. Click "Update List" button to list forwarded ports.
  4. Then click "Add New" button and fill the form. 
  5. If you check "IP" checkbox and type an IP, only requests from this IP will be redirected. So, do not fill it. 
  6. Internal port must be equal to our server's port.
  7. "Port" and "Internal port" don't have to be equal.

Adding new port forwarding entry

From now on all requests come to "externalip:port" will be redirected from the modem to our computer. To test the server if it is accessible from the internet you can use Just write your external IP and port as "http://externalip:port" and hit "Submit" button... 

Test result


  • 13 September 2012: The POST method was explained and supported.
  • 3 September 2012: First version.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Huseyin Atasoy
Turkey Turkey
I am interested in artificial intelligence, signal processing, electronics, robotics and internet/network technologies.

A few of my works:
KANO (Real-time Optical Mark Recognition)
Real-time object recognition
Real-time facial expression recognition

My blog

You may also be interested in...


Comments and Discussions

QuestionMy vote 5 Pin
Thunder Roid29-May-13 5:10
memberThunder Roid29-May-13 5:10 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun10-Apr-13 23:20
memberHumayun Kabir Mamun10-Apr-13 23:20 
Question.JS Pin
bedgear8-Mar-13 20:23
memberbedgear8-Mar-13 20:23 
AnswerRe: .JS Pin
Huseyin Atasoy11-Mar-13 0:38
memberHuseyin Atasoy11-Mar-13 0:38 
QuestionSimple WebServer Request Pin
scottie197211-Feb-13 9:03
memberscottie197211-Feb-13 9:03 
AnswerRe: Simple WebServer Request Pin
Huseyin Atasoy11-Feb-13 21:41
memberHuseyin Atasoy11-Feb-13 21:41 
GeneralMy vote of 5 Pin
soulprovidergr18-Dec-12 4:06
membersoulprovidergr18-Dec-12 4:06 
GeneralMy vote of 5 Pin
Mihai MOGA16-Oct-12 4:31
memberMihai MOGA16-Oct-12 4:31 
This is a great inspiring article. I am pretty much pleased with your good work. You put really very helpful information. Keep it up once again.
GeneralRe: My vote of 5 Pin
Huseyin Atasoy16-Oct-12 23:24
memberHuseyin Atasoy16-Oct-12 23:24 
GeneralMy vote of 5 Pin
adkalavadia9-Oct-12 20:02
memberadkalavadia9-Oct-12 20:02 
GeneralMy vote of 5 Pin
Olivier Giulieri8-Oct-12 15:55
memberOlivier Giulieri8-Oct-12 15:55 
GeneralMy vote of 5 Pin
SachinDakle7-Oct-12 23:11
memberSachinDakle7-Oct-12 23:11 
GeneralRe: My vote of 5 Pin
Huseyin Atasoy8-Oct-12 1:30
memberHuseyin Atasoy8-Oct-12 1:30 
GeneralMy vote of 5 Pin
kanalbrummer17-Sep-12 2:54
memberkanalbrummer17-Sep-12 2:54 
GeneralRe: My vote of 5 Pin
Huseyin Atasoy24-Sep-12 22:13
memberHuseyin Atasoy24-Sep-12 22:13 
GeneralMy vote of 5 Pin
Sanjay_00714-Sep-12 12:33
memberSanjay_00714-Sep-12 12:33 
GeneralRe: My vote of 5 Pin
Huseyin Atasoy24-Sep-12 22:09
memberHuseyin Atasoy24-Sep-12 22:09 
QuestionMy vote of 5 Pin
M I developer14-Sep-12 2:22
memberM I developer14-Sep-12 2:22 
AnswerRe: My vote of 5 Pin
Huseyin Atasoy24-Sep-12 22:08
memberHuseyin Atasoy24-Sep-12 22:08 
QuestionNice job Pin
sniper_vb13-Sep-12 0:36
membersniper_vb13-Sep-12 0:36 
AnswerRe: Nice job Pin
Huseyin Atasoy13-Sep-12 3:15
memberHuseyin Atasoy13-Sep-12 3:15 
Questionsupport ASP.NET? Pin
adriancs12-Sep-12 22:11
memberadriancs12-Sep-12 22:11 
AnswerRe: support ASP.NET? Pin
Huseyin Atasoy13-Sep-12 3:04
memberHuseyin Atasoy13-Sep-12 3:04 
GeneralMy vote of 5 Pin
Sharath279011-Sep-12 19:18
memberSharath279011-Sep-12 19:18 
GeneralRe: My vote of 5 Pin
Huseyin Atasoy11-Sep-12 20:29
memberHuseyin Atasoy11-Sep-12 20:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171114.1 | Last Updated 9 Oct 2012
Article Copyright 2012 by Huseyin Atasoy
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid