Monday, December 16, 2019

How to create HTTP Server in Java - ServerSocket Example


How to create HTTP Server in Java - ServerSocket Example
Java has a very good networking support, allows you to write client server application by using TCP Sockets. In this tutorial, we will learn how to create a simple HTTP Server in Java, which can listen HTTP request on a port let's say 80 and can send response to 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 request, there is no in built HTTP client library in JDK. Though there is no short of good open source library e.g. you can use Jsoup to parse HTML and can use Apache HttpClient library for sending GET and POST request 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. Book is very focused on practical and you will find lot of interesting example related to common networking task e.g. writing multi-threaded servers, using non blocking IO and using low level socket classes.

How to make HTTP Server in Java
First step to create a web server is to create a network socket which can accept connection on certain TCP port. HTTP server usually listen on port 80 but we will use a different port 8080 for testing purpose. 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 browser will wait forever. Don't believe? compile and try it now.
If your browser is smart and giving up after waiting for sometime then try telnet command. You should be able to connect to server and as soon as you stop your server telnet will show that "could not open connection to the host, on port 8080: connect failed" as shown in following screenshot.



So now we have a server which is listening for connection on port 8080 but we are not doing anything with incoming connection but we are not rejecting them either. All of them are waiting to be served and stored inside 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 server will be shutdown.

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 client you should close this socket and get ready to accept 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 previous connection, all it care for new incoming connections. This is endless cycle until server is stopped. Now let's see what is coming from browser in form of 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 request using InputStream opened from the client socket. It's better to use BufferedReader because browser will send multiple line. 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 request type is GET and 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 only thing remaining is to send 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 response, we need to get the output stream from socket and then we will write HTTP response code OK and today's date into 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 command line and connect to the http://localhost:8080 from Firefox,
you will see 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 connection, reading request and sending response. By using try-with-resource statement of Java 7, we have also simplified our code, because socket will automatically closed by Java once you are done with response. Only limitation of this server is that it can serve one client at a time. If request processing takes 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.



That's all about how to create 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 Server application and Socket is used to send and receive data from individual client.



No comments:

Post a Comment

Recent Post

Databricks Delta table merge Example

here's some sample code that demonstrates a merge operation on a Delta table using PySpark:   from pyspark.sql import SparkSession # cre...