Monday, August 9, 2010

Multi-threaded HTTP Server

My earlier post on creating a single threaded HTTP/1.0 Server using Java gave an idea about how to implement an HTTP server. This post is an extension to the same program. I have implemented a Multi-threaded version of the same server. The source code is given below.

Implementation
A new thread is spawned upon receiving a connection request from a client. This socket is used to transfer data between these two end-systems. Since the server implements HTTP/1.0, the connection is terminated after the request is satisfied by the server.

The code is available here.

Multi-threaded server

/*
* Coded By: Rahul Krishnan
*/

import java.net.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;

class MTServer implements Runnable {
// Socket available to all the methods in the class.
private Socket connectionSocket;

// Constructor.
MTServer (Socket sock) {
connectionSocket = sock;
}

// Main starts here.
public static void main(String argv[]) throws Exception {
// Listen to the client connection.
ServerSocket listenSocket = new ServerSocket(4444);

// Spawn threads for all the new connections.
while (true) {
Socket connectionSocket = listenSocket.accept();
Thread T = new Thread(new MTServer(connectionSocket));
T.start();
}
}

// Thread code.
public void run() {
String httpReqMsg = null; // Strores the request from client.
String fileName = null; // Stores the file name to be fetched.
BufferedReader inFromClient = null; // Input Stream - from the client.
DataOutputStream outToClient = null;// Output Stream - to client.
FileInputStream inFile = null; // Input Stream - from file.

try {
inFromClient = new BufferedReader(
new InputStreamReader(connectionSocket.getInputStream()));
outToClient = new DataOutputStream(
connectionSocket.getOutputStream());

// Read the request from client.
httpReqMsg = inFromClient.readLine();
}
catch (IOException exception) {
exception.printStackTrace();
}

StringTokenizer tokenizedLine = new StringTokenizer(httpReqMsg);
// Extract the file name.
if (tokenizedLine.nextToken().equals("GET")) {
fileName = tokenizedLine.nextToken();

// Process the file name.
if (fileName.startsWith("/") == true) {
// Extract the portion after '/' in the file name.
fileName = fileName.substring(1);
}

// Access the file.
File file = new File(fileName);
int numOfBytes = (int) file.length();

byte[] fileInBytes = new byte[numOfBytes];

try {
inFile = new FileInputStream(fileName);
}
catch (FileNotFoundException exception) {
exception.printStackTrace();
}

try {
inFile.read(fileInBytes);
}
catch (IOException exception) {
exception.printStackTrace();
}

try {
// Server response message starts.
outToClient.writeBytes("HTTP/1.0 200 OK\r\n");

// Send the content type.
if (fileName.endsWith(".jpg")) {
outToClient.writeBytes("Content-Type: image/jpeg\r\n");
}
if (fileName.endsWith(".gif")) {
outToClient.writeBytes("Content-Type: image/gif\r\n");
}
// Send the content length.
outToClient.writeBytes("Content-Lenght: " + numOfBytes + "\r\n");

// Important : comply with the HTTP reply format.
outToClient.writeBytes("\r\n");
// Write the file into the output stream.
outToClient.write(fileInBytes, 0, numOfBytes);
connectionSocket.close();
}
catch (IOException exception) {
exception.printStackTrace();
}
}
}
}

No comments:

Post a Comment