A Simple HTTP Server - Part 1

NodeJs has built-in http modules that allow developers to build web applications without the need to configure and run a proprietary HTTP server such as Apache or Nginx. Other programming languages provide similar libraries that allow developers to bundle a server with an application. So in this article, we'll take a look at how easy it is to write a simple single-threaded HTTP server in Java. Once we're done, we can run a simple test using Apaches ab tool to determine how many requests per second the server can handle.

Contents


A Simple HTTP Server - Part 1
A Simple HTTP Server - Multi Threading - Part 2
A Simple HTTP Server - ThreadPool - Part 3

ServerSocket Class


The ServerSocket is a class found in the java.net package. An instance of ServerSocket is configured to listen on a port number and can also be bound to an IP address. Listing 1 below shows how to setup a ServerSocket that listens on port 9000 and continually waits for connections.

Listing 1

import java.net.*;
...
ServerSocket server = new ServerSocket(9000));

while (true){
    Socket client = server.accept();
}

The accept() method is a blocking method. The server will wait until a client connection is established. Once the server accepts a client connection, we can use the BufferedReader/BufferedWriter classes to read and write to the streams. Listing 2 below, shows how to read all the data sent by the client.

Listing 2

...

// Get A BufferedReader/BufferedWriter to handle reading and writing to the stream.

BufferedReader requestReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedWriter responseWriter = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));

// Important, we need to read all the data sent from the client before we can send a response.
while (true){
    String headerLine = requestReader.readLine();

    if (headerLine.length() == 0){
        break;
    }
}

The first line of the request data specifies the HTTP method and the resource the client is requesting. The client will then send request headers each on a new line, finally ending with a blank line. For simplicity, we can read lines from the client using a while loop and only break when we come across a blank line. Once all the data has been read, we can finally issue a response. Note, that the request body is being ignored. So in the case of a post request, the post data will not be captured. Listing 3 below is the complete server code.

Listing 3

import java.net.*;
import java.io.*;

class HttpServer{

    public static void main(String args[]){

        try{

            // Create a new server socket and listen on port 9000
            try (ServerSocket server = new ServerSocket(9000)){

                // Continue to listen for client connections
                while (true){

                    // Accept a client connection. accept() is a blocking method.
                    Socket client = server.accept();

                    try{

                        // Get A BufferedReader/BufferedWriter to handle reading and writing to the stream.

                        BufferedReader requestReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                        BufferedWriter responseWriter = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));

                        while (true){
                            String headerLine = requestReader.readLine();

                            if (headerLine.length() == 0){
                                break;
                            }
                        }

                        // How original is this?
                        responseWriter.write("Hello World\n");
                        responseWriter.flush();

                        // the client connection will close, both the input and output streams.
                        client.close();

                    }catch(IOException e){
                        try{
                            if(client != null){
                                client.close();
                            }
                        }catch(IOException e2){

                        }
                    }
                }
            }

        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

Testing With ab (Apache HTTP server benchmarking tool)


ab is a command line tool that is shipped with Apache (It can also be downloaded separately) and used to benchmark a server. It provides some basic insights into how well a server is performing. We can use it to determine how many requests per second the HTTP server can handle. The following ab command will issue 100 requests using 10 as the concurrency level.

ab -n 100 -c 10 http://127.0.0.1:9000/
The ab command above produced the following results. Looking at the results we can see that the server is capable of handling 4579 requests per second.

Listing 4

ab -n 100 -c 10 http://127.0.0.1:9000/


Server Software:        
Server Hostname:        127.0.0.1
Server Port:            9000

Document Path:          /
Document Length:        0 bytes

Concurrency Level:      10
Time taken for tests:   0.022 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      1200 bytes
HTML transferred:       0 bytes
Requests per second:    4579.38 [#/sec] (mean)
Time per request:       2.184 [ms] (mean)
Time per request:       0.218 [ms] (mean, across all concurrent requests)
Transfer rate:          53.66 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:     0    0   0.0      0       0
Waiting:        0    0   0.0      0       0
Total:          0    0   0.0      0       0

Percentage of the requests served within a certain time (ms)
  50%      0
  66%      0
  75%      0
  80%      0
  90%      0
  95%      0
  98%      0
  99%      0
 100%      0 (longest request)

Java

Rust

SAP Business One

Node.js

HANA DB