Re: NIO best practice
- From: "John" <john.casey@xxxxxxxxx>
- Date: 12 Jun 2006 04:36:25 -0700
EJP wrote:
John wrote:
Thanks for all your suggestions that was great :)
Let us know how you're getting along after these improvements.
Well the code is still a little bit of a work in progress but I have
integrated your suggestions into the following code base. Its amazing
how simple it is to implement persistant connections in http. I had
originally thought it was going to be a little tougher buts its amazing
how easy really is! :)
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
class ChannelState
{
public ChannelState(FileChannel fchannel, long position, long total,
ByteBuffer buffer) {
this.fchannel=fchannel;
this.position=position;
this.total_file_size=total;
this.buffer=buffer;
}
public FileChannel fchannel;
public ByteBuffer buffer;
public long position;
public long total_file_size;
}
public class webserver
{
public static void main(String[] args)
{
//File wwwBase=new File("h:/workspace/web server/");
//File wwwBase=new File("/home/jacasey/workspace/web server/");
File wwwBase=new File("c:/Eclipse/workspace/web server/");
try {
ServerSocketChannel channel= ServerSocketChannel.open();
InetSocketAddress address=new InetSocketAddress(8080);
channel.socket().bind(address);
channel.configureBlocking(false);
Selector selector=Selector.open();
channel.register(selector,SelectionKey.OP_ACCEPT);
while(true)
{
int n=selector.select();
if(n==0)
{
continue;
}
Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> ready = readyKeys.iterator();
while(ready.hasNext())
{
SelectionKey selkey=ready.next();
ready.remove();
try
{
if(selkey.isValid()==false)
{
continue;
}
else if(selkey.isAcceptable())
{
ServerSocketChannel server=(ServerSocketChannel)
selkey.channel();
SocketChannel client=server.accept();
if(client==null)
continue;
client.configureBlocking(false);
client.register(selector,SelectionKey.OP_READ);
ByteBuffer buffer=ByteBuffer.allocate(32768);
SelectionKey key=client.keyFor(selector);
key.attach(buffer);
}
else if(selkey.isReadable())
{
handle_ready_read(wwwBase,selkey);
}
else if(selkey.isWritable())
{
handle_write_ready(selector, selkey);
}
}
catch(IOException err)
{
selkey.channel().close();
err.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void handle_write_ready(Selector selector, SelectionKey
selkey) throws IOException, ClosedChannelException {
SocketChannel client=(SocketChannel) selkey.channel();
ChannelState state=(ChannelState) selkey.attachment();
if(state.buffer!=null)
{
client.write(state.buffer);
if(state.buffer.hasRemaining())
{
state.buffer.compact();
client.register(selkey.selector(),SelectionKey.OP_WRITE);
selkey.attach(state);
}
else
{
transfer_file(selkey, client, state);
}
}
else
{
transfer_file(selkey, client, state);
}
}
public static void handle_ready_read(File wwwBase, SelectionKey
selkey) throws IOException, MalformedURLException,
FileNotFoundException
{
ByteBuffer buffer=(ByteBuffer) selkey.attachment();
SocketChannel client=(SocketChannel) selkey.channel();
long BYTES_READ=client.read(buffer);
int position=buffer.position();
buffer.flip();
if(BYTES_READ>=4)
{
// String tmp=new String(buffer.array());
// System.err.println(tmp);
boolean short_read = process_request(buffer);
if(short_read==false)
{
// determine what sort of request it is
String requestMethod="";
String queryString = process_query_string(buffer, requestMethod);
File data=new File(wwwBase+queryString);
FileInputStream fis=new FileInputStream(data);
FileChannel fchannel=fis.getChannel();
// use the inbuilt class to guess the type of data we are going to
write back to the client
String contentType="application/octed-stream";
System.out.println("request: "+data.toString());
contentType=URLConnection.guessContentTypeFromName(data.toString());
if(data.isFile())
{
StringBuffer output=new StringBuffer();
output.append("HTTP/1.0 200 OK\r\n");
output.append("Server: proxy\r\n");
//output.append("Connection: close\r\n"); // eventually I will
have to detect whether a client is capable of persistance OK for now.
output.append("Connection: keep-alive\r\n");
output.append("Content-Type: "+contentType+"\r\n");
output.append(("Content-Length: "+data.length()+"\r\n"));
output.append("\r\n");
buffer.clear();
buffer.put(output.toString().getBytes());
buffer.flip();
client.write(buffer);
if(buffer.hasRemaining())
{
// short header write
buffer.compact();
client.register(selkey.selector(),SelectionKey.OP_WRITE);
selkey.attach(buffer);
}
else
{
transfer_file(selkey, client, new ChannelState(fchannel, 0,
data.length(),buffer));
}
}
else
{
// file does not exist
}
}
else
{
// short read
client.register(selkey.selector(),SelectionKey.OP_READ);
// reset the buffer so that we can read more data in
buffer.position(position);
buffer.limit(buffer.capacity());
selkey.attach(buffer);
}
}
else if(BYTES_READ>0)
{
// short read
client.register(selkey.selector(),SelectionKey.OP_READ);
// reset the buffer so that we can read more data in
buffer.position(position);
buffer.limit(buffer.capacity());
selkey.attach(buffer);
}
else if(BYTES_READ==-1)
{
System.err.println("closed");
client.close();
}
}
public static String process_query_string(ByteBuffer buffer, String
requestMethod) {
byte[] request=new byte[buffer.position()];
buffer.flip();
buffer.get(request);
buffer.clear();
int i=0;
for(;i<request.length;i++)
{
if(request[i]==' ')
{
i++;
break;
}
requestMethod+=(char)request[i];
}
// extract the query_string if we are dealing with a get request
StringBuffer queryString=new StringBuffer(100);
if(requestMethod.equalsIgnoreCase("GET"))
{
for(;i<request.length;i++)
{
if(request[i]==' ')
break;
queryString.append((char)request[i]);
}
}
else
{
System.err.println("unhandled method"+requestMethod);
// unhandled method
}
return queryString.toString();
}
public static boolean process_request(ByteBuffer buffer) {
boolean short_read=false;
byte END_HTTP[]="\r\n\r\n".getBytes();
byte END_OF_REQUEST[]=new byte[4];
buffer.position(buffer.limit()-4);
buffer.get(END_OF_REQUEST,0,4);
for(int j=0;j<END_OF_REQUEST.length;j++)
{
if(END_HTTP[j]!=END_OF_REQUEST[j])
{
short_read=true;
break;
}
}
return short_read;
}
public static void transfer_file(SelectionKey selkey, SocketChannel
client, ChannelState cs) throws IOException, ClosedChannelException {
ByteBuffer buffer=cs.buffer;
// pipe the file channel data back to our socket channel
long write=cs.fchannel.transferTo(cs.position,32768,client);
// if we have a short write select OP_WRITE
if(cs.position+write<cs.total_file_size)
{
client.register(selkey.selector(),SelectionKey.OP_WRITE);
cs.position+=write;
selkey.attach(cs);
}
else
{
cs.fchannel.close();
client.register(selkey.selector(),SelectionKey.OP_READ);
buffer.clear();
selkey.attach(buffer);
}
}
}
.
- References:
- NIO best practice
- From: John
- Re: NIO best practice
- From: EJP
- Re: NIO best practice
- From: John
- Re: NIO best practice
- From: EJP
- NIO best practice
- Prev by Date: Re: Deadlocks on IO in jdk1.5.0_06
- Next by Date: Re: whats use of ":" in java in the following code ?
- Previous by thread: Re: NIO best practice
- Next by thread: i like to project video conferencing in java
- Index(es):
Relevant Pages
|