自己动手编写tomcat服务器(一)

来源:互联网 发布:先导化合物的优化方法 编辑:程序博客网 时间:2024/05/25 01:35

这篇博文来自于《how tomcat works》一书的第一章

我们的服务器程序由下列三个类组成:

     HttpServer.java

     Request.java

     Response.java

HttpServer.java是程序的入口。它的main方法创建了一个HttpServer的实例,然后调用它的await方法,此方法等待客户端的

HTTP请求,处理请求,把响应传回客户端。此服务器程序只能处理静态的资源,如HTML文件和图片文件。


我们来看看HttpServer.java的源代码

import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;public class HttpServer {/** * WEB_ROOT是存放HTML文件的目录 */public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";//关闭命令private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";//收到关闭命令private boolean shutdown = false;/** * @param args */public static void main(String[] args) {HttpServer server = new HttpServer();server.await();}public void await() {ServerSocket serverSocket = null;int port = 8080;try{serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); }catch(IOException e){e.printStackTrace();System.exit(1);}//等待请求while(!shutdown){Socket socket = null;InputStream inputStream = null;OutputStream outputStream = null;try{socket = serverSocket.accept();inputStream = socket.getInputStream();outputStream = socket.getOutputStream();//创建请求对象并解析Request request = new Request(inputStream);request.parse();//创建响应对象Response response = new Response(outputStream);response.setRequest(request);response.sendStaticResource();//关闭socketif(socket != null){ socket.close();}  //检查URI是否是一个关闭命令shutdown = SHUTDOWN_COMMAND.equals(request.getUri());}catch(Exception e){e.printStackTrace();continue;}}}}

Request.java类代表一个HTTP请求,它的构造方法传入一个InputStream输入流,该输入流来自于与客户端交流的那个socket,即ServerSocket的accept方法返回的那个socket对象。下面是Request.java类的源代码:

import java.io.IOException;import java.io.InputStream;public class Request {private InputStream inputStream;private String uri;public Request(InputStream inputStream) {this.inputStream = inputStream;}public void parse(){StringBuffer request = new StringBuffer(2048);int i;byte[] buffer = new byte[2048];try{i = inputStream.read(buffer);}catch(IOException e){e.printStackTrace();i = -1;}for(int j=0;j<i;j++){request.append((char)buffer[j]);}System.out.println(request.toString());uri = parseUri(request.toString());}private String parseUri(String requestString){int index1,index2;index1 = requestString.indexOf(" ");if(index1 != -1){index2 = requestString.indexOf(" ",index1 + 1);if(index2 > index1)return requestString.substring(index1+1,index2);return null;}else{return null;}}public String getUri() {return uri;}public void setUri(String uri) {this.uri = uri;}}


方法parse()用来解析HTTP请求的数据。方法parseUri()根据传入的请求数据(一个字符串)解析出HTTP请求的URI,如GET  /index.html  HTTP/1.1中的 /index.html

就是一个HTTP请求的URI,方法parseUri()是通过搜索请求的第一个空格和第二个空格间的字符串来得到URI的。


Response.java类代表一个HTTP响应,源代码如下:


import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;public class Response {private static final int BUFFER_SIZE = 1024;Request request;OutputStream outputStream;public Response(OutputStream outputStream) {this.outputStream =outputStream;}public void setRequest(Request request) {this.request = request;}public void sendStaticResource() throws IOException{byte bytes[] = new byte[BUFFER_SIZE];FileInputStream fis = null;try{File file = new File(HttpServer.WEB_ROOT,request.getUri());if(file.exists()){fis = new FileInputStream(file);int ch = fis.read(bytes,0,BUFFER_SIZE);while(ch != -1){outputStream.write(bytes, 0, ch);ch = fis.read(bytes,0,BUFFER_SIZE);}}else{String errorMessage = "<h1>File not found</h1>";outputStream.write(errorMessage.getBytes());}}catch(Exception e){   System.out.println(e.toString());}finally{if(fis != null)fis.close();}}}

Response类的构造方法传入一个OutputStream输出流,此输出流来自于socket的getOutputStream()方法,而此socket又来自于ServerSocket的accept方法返回的对象

Response类的sendStaticResource()方法先找到HTTP请求头的URI所代表的文件,将此文件读入到一个字节数组,再用OutputStream输出流将字节数组写入到客户端

的浏览器。如果URI所代表的文件不存在,就向浏览器写入一个错误信息。


启动HttpServer类,在浏览器中输入http://localhost:8080/index.html,(可以自己在此web工程的WebRoot根目录下新建一个index.html文件),你将看到index.html在浏览器

中显示出来。