How tomcat work连载一:简易的静态WEB容器

        以下代码是我在学习《HOW Tomcat work》第一章:如何构建一个简单的静态文件容器后,写下的,注释很详细,不懂的可以站内短信我.

       首先建立一个监听Server类,如下所示:

        package ex01.pyrmont;

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;
import java.util.Date;

import org.apache.log4j.Logger;

/**
 * 类HttpServer.java的实现描述:
 */
public class HttpServer {

    public static final Logger log       = Logger.getLogger("actionLog");

    /** 获取当前的文件系统路径 **/
    public static final String WEB_ROOT  = System.getProperty("user.dir") + File.separator + "webRoot";

    /** 关闭的命令 **/
    public static final String SHUT_DOWN = "/shutdown";

    private ServerSocket       server;

    /**
     * 构造监听server
     * 
     * @param port 监听的端口
     * @param backlog 监听队列的最大长度
     * @param serverName 主机名(可以是域名或者是IP)
     */
    public HttpServer(int port, int backlog, String serverName){
        try {
            server = new ServerSocket(port, backlog, InetAddress.getByName(serverName));
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }

    }

    public static void main(String[] args) {
        HttpServer server = new HttpServer(8773, 1, "127.0.0.1");
        try {
            server.listen();
            /** 当监听终止的时候,释放相关资源 **/
            server.close();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 启动server的监听程序<br/>
     * 当在等待连接的时候,该方法可能会抛出<code>IOException</code><br/>
     * 例如server意外关闭等等
     * 
     * @throws IOException
     */
    public void listen() throws IOException {
        if (log.isInfoEnabled()) {
            log.info("server begin to listen on :" + new Date());
        }
        boolean isShutdown = false;
        Socket client = null;
        InputStream is = null;
        OutputStream os = null;
        Request request;
        Response response;
        while (!isShutdown) {
            client = server.accept();
            if (log.isInfoEnabled()) {
                log.info("get Client:" + client);
            }
            is = client.getInputStream();
            os = client.getOutputStream();
            /** 构造请求 **/
            request = new Request(is);
            /** 提取请求中的参数 **/
            request.parse();
            response = new Response(request);
            response.setOutput(os);
            /** 发送静态资源 **/
            response.sendStaticMessage();
            /** 关闭当前客户端 **/
            client.close();
            /** 判断是否是关闭命令 **/
            isShutdown = request.getUri().equalsIgnoreCase(SHUT_DOWN);
        }
    }

    /**
     * 关闭server
     */
    public void close() {
        if (server != null && !server.isClosed()) {
            try {
                if (log.isInfoEnabled()) {
                    log.info("server end to listen on :" + new Date());
                }
                server.close();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }
}

 

      建立一个对应静态文件的请求类:

     package ex01.pyrmont;

import java.io.IOException;
import java.io.InputStream;

import org.apache.log4j.Logger;

/**
 * 类Request.java的实现描述:
 */
public class Request {

    private static final Logger log = Logger.getLogger("actionLog");
    private InputStream         is;
    private String              uri;

    public Request(InputStream is){
        this.is = is;
    }

    /**
     * 读取request的内容,并提炼出uri
     */
    public void parse() {
        StringBuffer sb = new StringBuffer(2048);
        byte[] buffers = new byte[2048];
        int i;
        try {
            i = is.read(buffers);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            i = -1;
        }
        for (int j = 0; j < i; j++) {
            sb.append((char) buffers[j]);
        }
        if (log.isInfoEnabled()) {
            log.info("request:" + sb.toString());
        }
        this.uri = parseUri(sb.toString());
    }

    private String parseUri(String request) {
        /** 解析HTTP请求的头部,像GET/POST /index.html HTTP1.1 **/
        int index1, index2;
        /** 获取第一个空格的位置 **/
        index1 = request.indexOf(' ');
        if (index1 > -1) {
            /** 从第一个空格之后,获取第二个空格的位置 **/
            index2 = request.indexOf(' ', index1 + 1);
            if (index2 > index1) {
                return request.substring(index1 + 1, index2);
            }
        }
        return null;
    }

    /**
     * 返回request的uri路径
     * 
     * @return uri
     */
    public String getUri() {
        return uri;
    }

    @Override
    public String toString() {
        return String.format("Request[uri=%s]", this.uri);
    }
}

 

      建立响应输出类:

        package ex01.pyrmont;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.log4j.Logger;

/**
 * 类Response.java的实现描述:
 */
public class Response {

    private static final Logger log         = Logger.getLogger("actionLog");

    /** 缓冲区的大小 **/
    private static final int    BUFFER_SIZE = 1024;
    private Request             request;
    private OutputStream        output;

    public Response(Request request){
        this.request = request;
    }

    /**
     * 初始化一个输出的缓冲流
     * 
     * @param os
     */
    public void setOutput(OutputStream os) {
        output = os;
    }

    /**
     * 发送静态消息
     */
    public void sendStaticMessage() {
        InputStream is = null;
        String uri = request.getUri();
        /** 如果uri为null或者等同与关闭命令时候,直接返回 **/
        if (uri == null || uri.equalsIgnoreCase(HttpServer.SHUT_DOWN)) {
            return;
        }
        try {
            File file = new File(HttpServer.WEB_ROOT, uri);
            /** 如果静态资源文件找不到,则输出一个错误提示页面 **/
            if (!file.exists()) {
                log.warn("can't find uri:" + uri);
                String outputHtml = "<html>" + "<body>" + "<div><h1>can't find your response:" + uri + "</h1></div>"
                                    + "</body>" + "</html>";
                output.write(outputHtml.getBytes());
            } else {
                is = new FileInputStream(file);
                byte[] buffers = new byte[BUFFER_SIZE];
                /** 读入缓冲区的总字节数 **/
                int ch = is.read(buffers, 0, BUFFER_SIZE);
                while (ch != -1) {
                    output.write(buffers, 0, ch);
                    ch = is.read(buffers, 0, BUFFER_SIZE);
                }
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        closeResponse(is);
    }

    /**
     * 逆序的关闭响应的输出流,并输出响应文件
     * 
     * @param is
     * @param isr
     * @param br
     */
    private void closeResponse(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }
} 

 

    最后我们测试下:

    建立一个简单的HTML文件,如下所示:

    <html>

<body>
	<h1>welcome to Sweet's home</h1>
</body>
</html>
 

    试着在浏览器里输入http://127.0.0.1:8773/index.html,是不是可以看到这个欢迎页面

    如果输入http://127.0.0.1:8773/other.html(一个不存在的页面),是不是可以看到我们的错误页面提示

    如果输入http://127.0.0.1:8773/shutdown,可以看到我们的简易服务器正常关闭。

posted @ 2012-05-07 16:21  老去的JAVA程序员  阅读(167)  评论(0编辑  收藏  举报