用Java编写你自己的简单HTTP服务器(4)

JHTTP类的main()方法根据args[0]设置文档的根目录。端口从args[1]读取,或者使用默认的80.然后构造一个新的JHTTP线程并启动。此JHTTP线程生成50个RequestProcessor线程处理请求,每个线程在可用时从RequestProcessor池获取入站连接请求。JHTTP线程反复地接受入站连接,并将其放在RequestProcessor池中。每个连接由下例所示的RequestProcessor类的run()方法处理。此方法将一直等待,直到从池中得到一个Socket。一旦得到Socket,就获取输入和输出流,并链接到阅读器和书写器。接着的处理,除了多出文档目录、路径的处理,其他的同单文件服务器。

import Java.io.BufferedInputStream;   import java.io.BufferedOutputStream;   import java.io.DataInputStream;   import java.io.File;   import java.io.FileInputStream;   import java.io.IOException;   import java.io.InputStreamReader;   import java.io.OutputStream;   import java.io.OutputStreamWriter;   import java.io.Reader;   import java.io.Writer;   import java.net.Socket;   import java.util.Date;   import java.util.List;   import java.util.LinkedList;   import java.util.StringTokenizer;         public class RequestProcessor implements Runnable {          private static List pool=new LinkedList();       private File documentRootDirectory;       private String indexFileName="index.html";              public RequestProcessor(File documentRootDirectory,String indexFileName) {           if (documentRootDirectory.isFile()) {               throw new IllegalArgumentException();           }           this.documentRootDirectory=documentRootDirectory;           try {               this.documentRootDirectory=documentRootDirectory.getCanonicalFile();           } catch (IOException e) {           }                      if (indexFileName!=null) {               this.indexFileName=indexFileName;           }       }              public static void processRequest(Socket request) {           synchronized (pool) {               pool.add(pool.size(),request);               pool.notifyAll();           }       }              @Override       public void run() {           //安全性检测            String root=documentRootDirectory.getPath();                      while (true) {               Socket connection;               synchronized (pool) {                   while (pool.isEmpty()) {                       try {                           pool.wait();                       } catch (InterruptedException e) {                       }                                          }                   connection=(Socket)pool.remove(0);               }                              try {                   String fileName;                   String contentType;                   OutputStream raw=new BufferedOutputStream(connection.getOutputStream());                   Writer out=new OutputStreamWriter(raw);                   Reader in=new InputStreamReader(new BufferedInputStream(connection.getInputStream()), "ASCII");                                      StringBuffer request=new StringBuffer(80);                   while (true) {                       int c=in.read();                       if (c=='\t'||c=='\n'||c==-1) {                           break;                       }                       request.append((char)c);                   }                                      String get=request.toString();                   //记录日志                    System.out.println(get);                                      StringTokenizer st=new StringTokenizer(get);                   String method=st.nextToken();                   String version="";                   if (method=="GET") {                       fileName=st.nextToken();                       if (fileName.endsWith("/")) {                           fileName+=indexFileName;                       }                       contentType=guessContentTypeFromName(fileName);                       if (st.hasMoreTokens()) {                           version=st.nextToken();                       }                                              File theFile=new File(documentRootDirectory,fileName.substring(1,fileName.length()));                       if (theFile.canRead()&&theFile.getCanonicalPath().startsWith(root)) {                           DataInputStream fis=new DataInputStream(new BufferedInputStream(new FileInputStream(theFile)));                           byte[] theData=new byte[(int)theFile.length()];                           fis.readFully(theData);                           fis.close();                           if (version.startsWith("HTTP ")) {                               out.write("HTTP/1.0 200 OK\r\n");                               Date now=new Date();                               out.write("Date: "+now+"\r\n");                               out.write("Server: JHTTP 1.0\r\n");                               out.write("Content-length: "+theData.length+"\r\n");                               out.write("Content-Type: "+contentType+"\r\n\r\n");                               out.flush();                           }                           raw.write(theData);                           raw.flush();                       }else {                           if (version.startsWith("HTTP ")) {                               out.write("HTTP/1.0 404 File Not Found\r\n");                               Date now=new Date();                               out.write("Date: "+now+"\r\n");                               out.write("Server: JHTTP 1.0\r\n");                               out.write("Content-Type: text/html\r\n\r\n");                               out.flush();                           }                           out.write("<HTML>\r\n");                           out.write("<HEAD><TITLE>File Not Found</TITLE></HRAD>\r\n");                           out.write("<BODY>\r\n");                           out.write("<H1>HTTP Error 404: File Not Found</H1>");                           out.write("</BODY></HTML>\r\n");                       }                   }else {//方法不等于"GET"                        if (version.startsWith("HTTP ")) {                           out.write("HTTP/1.0 501 Not Implemented\r\n");                           Date now=new Date();                           out.write("Date: "+now+"\r\n");                           out.write("Server: JHTTP 1.0\r\n");                           out.write("Content-Type: text/html\r\n\r\n");                           out.flush();                       }                       out.write("<HTML>\r\n");                       out.write("<HEAD><TITLE>Not Implemented</TITLE></HRAD>\r\n");                       out.write("<BODY>\r\n");                       out.write("<H1>HTTP Error 501: Not Implemented</H1>");                       out.write("</BODY></HTML>\r\n");                   }                                  } catch (IOException e) {               }finally{                   try {                       connection.close();                   } catch (IOException e2) {                   }                                  }           }       }              public static String guessContentTypeFromName(String name) {           if (name.endsWith(".html")||name.endsWith(".htm")) {               return "text/html";           }else if (name.endsWith(".txt")||name.endsWith(".java")) {               return "text/plain";           }else if (name.endsWith(".gif")) {               return "image/gif";           }else if (name.endsWith(".class")) {               return "application/octet-stream";           }else if (name.endsWith(".jpg")||name.endsWith(".jpeg")) {               return "image/jpeg";           }else {               return "text/plain";           }       }      }  

不足与改善:

这个服务器可以提供一定的功能,但仍然十分简单,还可以添加以下的一些特性:

(1)       服务器管理界面

(2)       支持CGI程序和Java Servlet API

(3)       支持其他请求方法

(4)       常见Web日志文件格式的日志文件

(5)       支持多文档根目录,这样各用户可以有自己的网站

最后,花点时间考虑一下可以采用什么方法来优化此服务器。如果真的希望使用JHTTP运行高流量的网站,还可以做一些事情来加速此服务器。第一点也是最重要的一点就是使用即时编译器(JIT),如HotSpot。JIT可以将程序的性能提升大约一个数量级。第二件事就是实现智能缓存。记住接受的请求,将最频繁的请求文件的数据存储在Hashtable中,使之保存在内存中。使用低优先级的线程更新此缓存。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/8d09c9042ad69928ea83361c96d271a7.html