Pool Thread Web Server - Need Help Implementing HTTP 1.1 keep alive

Hi guys, I have a pretty simple webserver, just 3 classes, very simple, but now I need to add HTTP 1.1 keep alive feature. I have two problems, 1) I'm not completely sure I understand the keep alive feature 2) I have no idea how to impliment it with my current code.

From my understanding HTTP 1.1 keep alive is used in order to reuse the socket so that you dont need to reopen it everytime. However, when you are listening to the serversocket and accepting new clients all the time, how can u figure out if you've already accepted the client before and already have a socket open? Okay sorry, I know I'm talking to much, i'll show my code, hopefully someone knows a simple way to impliment it.

Sincerely,

Hakim

package web;

import java.net.*;

publicfinalclass web{

publicstaticvoid main(String args[])throws Exception{

//The port of the webserver

int PORT = 5306;

ServerSocket listenSocket =new ServerSocket(PORT);

//The Queue that implements the ThreadPool

WorkQueue myserver =new WorkQueue(5);

//Run an infinite loop listening to the sockets and accepting more connections. It creates a new HTTPrequest to deal with the request and adds it to the queue to wait for execution

while(true){

HttpRequest request =new HttpRequest(listenSocket.accept());

myserver.execute(request);

}

}

}

package web;

import java.util.*;

publicclass WorkQueue

{

privatefinalint nThreads;

privatefinal Worker[] threads;

privatefinal LinkedList queue;

public WorkQueue(int nThreads)

{

this.nThreads = nThreads;

queue =new LinkedList();

threads =new Worker[nThreads];

for (int i=0; i<nThreads; i++){

threads[i] =new Worker();

threads[i].start();

}

}

publicvoid execute(Runnable r){

synchronized(queue){

queue.addLast(r);

queue.notify();

}

}

privateclass Workerextends Thread{

publicvoid run(){

Runnable r;

while (true){

synchronized(queue){

while (queue.isEmpty()){

try

{

queue.wait();

}

catch (InterruptedException ignored)

{

}

}

r = (Runnable) queue.removeFirst();

}

try{

r.run();

}

catch (RuntimeException e){

}

}

}

}

}

package web;

import java.io.*;

import java.net.*;

import java.util.*;

import java.lang.*;

import java.text.*;

finalclass HttpRequestimplements Runnable{

Socket socket;

staticfinal SimpleDateFormat webtime =new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");

public HttpRequest(Socket socket){

this.socket = socket;

}

publicvoid run(){

try{

processRequest();

}catch (Exception e){

System.out.println(e);

}

}

privatevoid processRequest()throws Exception{

//Get references to sockets input and output streams

InputStream is = this.socket.getInputStream();

DataOutputStream os =new DataOutputStream(this.socket.getOutputStream());

//Set up input stream filter

BufferedReader br =new BufferedReader(new InputStreamReader(is));

//Get the request line of HTTP message

String requestLine = br.readLine();

//Extract the filename (ie take the second token

//Sample HTTP 1.0 First Line HEADER

// GET /path/file.html HTTP/1.0

// First token = Type of command (Get or Post)

// Second token = Filename

// Third token = HTTP Protocal (1.0 or 1.1)

StringTokenizer tokens =new StringTokenizer(requestLine);

tokens.nextToken();

String fileName = tokens.nextToken();

// Drop the slash at the begginning if there is a slash.

if(fileName.charAt(0) =='/')

fileName = fileName.substring(1,fileName.length());

// Open the requested file.

FileInputStream fis =null;

boolean fileExists =true;

try{

fis =new FileInputStream(fileName);

}catch (FileNotFoundException e){

fileExists =false;

}

// Construct the response message.

String statusLine =null;

String header =null;

String entityBody =null;

if (fileExists){

statusLine ="HTTP/1.1 200 OK \r\n";

if(fileName.endsWith(".htm") || fileName.endsWith(".html"))

header ="Content-type: text/html \r\n";

elseif(fileName.endsWith(".jpg") || fileName.endsWith(".jpeg"))

header ="Content-type: image/jpeg \r\n";

elseif(fileName.endsWith(".gif"))

header ="Content-type: image/gif \r\n";

elseif(fileName.endsWith(".txt"))

header ="Content-type: text/plain \r\n";

else

header ="Content-type: application/octet-stream \r\n";

webtime.setTimeZone(TimeZone.getTimeZone("GMT"));

String lastModified = webtime.format(new Date());

header +="Last Modified: " + lastModified;

}else{

statusLine ="HTTP/1.1 404 Not Found \r\n";

header ="NONE";

entityBody ="\n\n Not Found";

}

// Send the status line.

os.writeBytes(statusLine);

// Send the content type line.

os.writeBytes(header);

System.out.println(header);

// Send a blank line to indicate the end of the header lines.

os.writeBytes("\r\n");

// Send the entity body.

if (fileExists){

byte[] buffer =newbyte[1024];

int bytes = 0;

// Copy requested file into the socket's output stream.

while((bytes = fis.read(buffer)) != -1 )

os.write(buffer, 0, bytes);

fis.close();

}else{

os.writeBytes(entityBody);

}

//Close the streams

os.close();

br.close();

socket.close();

}

}

>

[11936 byte] By [sadhakima] at [2007-11-26 16:46:46]
# 1

> However, when you are listening

> to the serversocket and accepting new clients all the

> time, how can u figure out if you've already accepted

> the client before and already have a socket open?

Because the request arrives on an existing connection, not a new one.

All you have to do at the server is change the sequence of processing an incoming connection from this:

read request

send reply

close connection

to this:

while (read request != EOF)

{

send reply

if (keep-alive header not set)

break

}

close the connection.

You should also set a reasonable read timeout on the accepted sockets, and close the connection if you get a timeout exception.

ejpa at 2007-7-8 23:14:13 > top of Java-index,Archived Forums,Socket Programming...
# 2

Thank you so much ejp, I have been reading books for the past week trying to figure this out, had no luck.

I'm just not sure about a couple of things, if you could clearify it for me.

At the moment, I am doing the processes in the following order

read request - main method

send reply - HTTPclass

close connection - HTTPclass

I think you are telling me to change when I close the connection, ie the HTTPclass should remain in a while loop for a while (unless the keep-alive is not set).. I did try that, but everytime a new request would come in, the main method would make a new HTTPclass object and service it, rather then the old one servicing it.

I dont quite understand this part

while (read request != EOF)

what does end of file have to do with it?

sorry, these are probably easy questions, i'm just really confused

Thanks again,

Hakim

sadhakima at 2007-7-8 23:14:13 > top of Java-index,Archived Forums,Socket Programming...
# 3
EOF is what your server's read method tells you when the client closes the socket, as eventually it will.
ejpa at 2007-7-8 23:14:13 > top of Java-index,Archived Forums,Socket Programming...