Saturday, July 31, 2021

How to create HTTP Server in Java - ServerSocket Example

Java has very good networking support, allows you to write client-server applications by using TCP Sockets. In this tutorial, we will learn how to create a simple HTTP Server in Java, which can listen to HTTP requests on a port let's say 80 and can send a response to the client. Being an HTTP Server, you can connect to it using your browser e.g. Chrome, Firefox, or Internet Explorer. Though HTTP is ubiquitous and present everywhere, Java doesn't have a dedicated API to create and parse HTTP requests, there is no in-built HTTP client library in JDK. 

Though there is no short of a good open source library e.g. you can use Jsoup to parse HTML and can use Apache HttpClient library for sending GET and POST requests right from your Java program. 

By the way, for those who wants to master network programming in Java, I suggest to read Java Network Programming, 4th Addition by Harold, Elliotte Rusty, its very comprehensive and not only covers both TCP/IP and UDP protocols, which are backbone of internet but also dive deep into the HTTP protocol, including REST, HTTP headers, and cookies. 

The book is very focused on practical and you will find a lot of interesting examples related to common networking tasks e.g. writing multi-threaded servers, using nonblocking IO, and using low-level socket classes.



How to make an HTTP Server in Java? Example

The first step to creating a web server is to create a network socket that can accept connections on a certain TCP port. HTTP servers usually listen on port 80 but we will use a different port 8080 for testing purposes. You can use ServerSocket class in Java to create a Server which can accept requests, as shown below


import java.net.ServerSocket;
public class SimpleHTTPServer {

  public static void main(String[] args) throws Exception {
    final ServerSocket server = new ServerSocket(8080);
    System.out.println("Listening for connection on port 8080 ....");
    while (true){
      // spin forever
    }
  }

}

That's enough to create a web server in Java. Now our server is ready and listening for incoming connection on port 8080. If you connect to http://localhost:8080 from your browser, the connection will be established and the browser will wait forever. 

Don't believe it? compile and try it now.
If your browser is smart and giving up after waiting for sometime then try the telnet command. You should be able to connect to the server and as soon as you stop your server telnet will show that "could not open a connection to the host, on port 8080: connect failed" as shown in the following screenshot.



So now we have a server that is listening for a connection on port 8080 but we are not doing anything with the incoming connection but we are not rejecting them either. All of them are waiting to be served and stored inside the server object. 

Do you see the while(true) loop? Any guess why we have that? This allows us to keep our program running, without this infinite loop our program will finish execution and the server will be shut down.

Now let's write code to start accepting connections. In Java, you can accept incoming connection by blocking call to accept() method, as shown below :

final Socket client = server.accept();

This is a blocking method and blocks until a client connects to the server. As soon as a client connect it returns the Socket object which can be used to read client request and send response to client. Once you are done with a client you should close this socket and get ready to accept the new incoming connection by calling accept() again. So basically, our HTTP server should work like this:

import java.net.ServerSocket;
import java.net.Socket;
public class SimpleHTTPServer {

  public static void main(String args[] ) throws Exception {
    final ServerSocket server = new ServerSocket(8080);
    System.out.println("Listening for connection on port 8080 ....");
    while (true) {
      final Socket client = server.accept();
      // 1. Read HTTP request from the client socket
      // 2. Prepare an HTTP response
      // 3. Send HTTP response to the client
      // 4. Close the socket
    }
  }
}

This is the standard HTTP Server, its simple because HTTP is stateless, which means it doesn't need to remember the previous connection, all it cares for new incoming connections. This is an endless cycle until the server is stopped. Now let's see what is coming from the browser in form of the HTTP request. 

When you connect to http://localhost:8080,your browser will send a GET HTTP request to the server. You can read the content of the request using InputStream opened from the client socket. It's better to use BufferedReader because the browser will send multiple lines. Here is the code to read request in your HTTP Server :

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleHTTPServer {

    public static void main(String args[] ) throws IOException {

        ServerSocket server = new ServerSocket(8080);
        System.out.println("Listening for connection on port 8080 ....");
        while (true) {
            Socket clientSocket = server.accept();
            InputStreamReader isr 
          =  new InputStreamReader(clientSocket.getInputStream());
            BufferedReader reader = new BufferedReader(isr);
            String line = reader.readLine();            
            while (!line.isEmpty()) {
                System.out.println(line);
                line = reader.readLine();
            }
        }
    }

}

When you connect to this server using Firefox it will spin endlessly but on server side you will see following lines on your console :

Listening for connection on port 8080 ....
GET / HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) 
Gecko/20100101 Firefox/36.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive

Our HTTP client (the Firefox browser) passes this text to our HTTP server written in Java. You can see that the request type is GET and the protocol used here is HTTP/1.1.

So now our server is not only listening for connection, but accepting it and also reading HTTP request. Now the only thing remaining is to send an HTTP response back to the client. To keep our server simple, we will just send today's date to the client. 

Let's see how we can do that. In order to send a response, we need to get the output stream from the socket, and then we will write HTTP response code OK and today's date into the stream.

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

/**
 * Java program to create a simple HTTP Server to demonstrate how to use
 * ServerSocket and Socket class.
 * 
 * @author Javin Paul
 */
public class SimpleHTTPServer {

    public static void main(String args[]) throws IOException {

        ServerSocket server = new ServerSocket(8080);
        System.out.println("Listening for connection on port 8080 ....");
        while (true) {
            try (Socket socket = server.accept()) {
                Date today = new Date();
                String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
                socket.getOutputStream()
                      .write(httpResponse.getBytes("UTF-8"));
            }
        }
    }

}

When you run the above program in Eclipse or from the command line and connect to the http://localhost:8080 from Firefox, you will see the following response :
Sun Mar 29 13:32:26 GMT+08:00 2015

Which is today's date. It means our HTTP Server is working properly, it is listening on port 8080, accepting connections, reading requests, and sending responses. By using the try-with-resource statement of Java 7, we have also simplified our code, because the socket will automatically be closed by Java once you are done with the response. The only limitation of this server is that it can serve one client at a time. 

If request processing takes a longer time, which is not in our case, the other connection has to wait. This problem can be solved by using threads or Java NIO non-blocking selectors and channels.

ServerSocket Example in Java


That's all about how to create an HTTP server in Java. This is a good example to learn network programming in Java. You have learned how to use ServerSocket and Socket class from this example. Remember, ServerSocket is used to receive connections in the Server application and Socket is used to send and receive data from the individual clients.

21 comments :

Unknown said...

Thank you, very helpful!!

Anonymous said...

Thank you, very helpful!!

Anonymous said...

appreciate it

Muhammad Saeed Javed said...

Well defined , Thank You

Unknown said...

Thank you so much! Very well written :)

satz said...

Thank You !!! Concise and very helpful :)

Anonymous said...

Do you know why mine is showing ERR_INVALID_HTTP_RESPONSE in the browser

Unknown said...

Hey, I want to know how to get the number of accesses to a file before closing the session... Any thoughts on that !!

Unknown said...

Awesome ..thanks

Anonymous said...

will the browser display the date??

Anonymous said...

The try with resource did not work as the http request handling was initiated in a new thread, to allow for multiple requests. The exception is that inputStream on the socket could not be established because socket isClosed. A little strange but in case it help others.

shashankgupta said...

Hi Javin,
I need some help, i want to make the request to the serversocket from my javascript with some data, i need to read this data and perform some task. Could you please guide me how to perform this.

Unknown said...

You can use a POST request. Print out what the server says when it recieves a POST response and build on top of that.

Unknown said...

Thank you thank you

Anonymous said...

I've done everything just as instructed but the localhost url just keeps loading forever not showing the date that gets sent to it.

Anonymous said...

very good

Anonymous said...

nice

Anonymous said...

It is not working. I run the code last, the console show "Listening for connection on port 8080" but the url http://localhost:8080 goes in an infinite loading and the date is not showed.

javin paul said...

Obviously, becuase you may be trying the first version which loops infinitely
while (true){
// spin forever
}

Try the other versions subsequently

Anonymous said...

I am actually grateful to the holder of this website who has
shared this wonderful article at at this time.

Anonymous said...

very nicely explained

Post a Comment