深入剖析Tomcat讀書筆記(1)——tomcat的連線本質

wuhulala發表於2017-02-19

備註:此書的版本為Tomcat4.0 ,還是原始的BIO連線方式,還沒有看完 ,過不涉及NIO

1 .HTTP請求與響應

請求報文

GET /asd HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6

響應

//response header  表示這是遵循http協議的
HTTP/1.1 200 OK
content-type:text/html


//response Body
<h1>Hello asd</h1>
<h2>shutdown_command:/shutdown</h2>

那麼tomcat的作用就是接受請求報文並返回相應的響應報文。實現了這個功能就相當於實現主要功能。

2 . 實現

在學習java的實時通訊的時候我們使用的就是socket(套接字)實現的。開一個SocketServer類接受客戶端請求,並且同時會生成一個socket來處理客戶端的請求。接收到請求之後我們就可以socket的輸出流進行返回報文。若想要瀏覽器識別,就要遵循http協議。

比如我們實現一個在瀏覽器地址輸入127.0.0.1:8080/name 返回報文是 Hello name!

//MyHttpServer.java
package com.wuhulala.chap1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * http伺服器類
 * 
 * @author xueaohui
 * @version 1.0
 * @date 2017/2/19
 */
public class MyHttpServer {
    //地址
    private static final String HTTP_HOST = "127.0.0.1";
    //埠
    private static final int HTTP_PORT = 8080;
    //停止伺服器命令
    private static final String SHUTDOWN_COMMAND = "/shutdown";


    public static void main(String[] args) {
        MyHttpServer server = new MyHttpServer();
        System.out.println(">>>>>>>>>啟動伺服器ing<<<<<<<<<<");

        server.await();
    }

    private void await() {

        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(HTTP_PORT, 1, InetAddress.getByName(HTTP_HOST));
        } catch (IOException e) {
            System.out.println(">>>>>>>>>啟動伺服器異常<<<<<<<<<<");
            e.printStackTrace();
            System.exit(1);
        }
        System.out.println(">>>>>>>>>啟動伺服器成功<<<<<<<<<<");

        boolean shutdown = false;
        while(!shutdown){
            Socket client = null;
            InputStream input = null;
            OutputStream out = null;

            try {
                client = serverSocket.accept();

                input = client.getInputStream();
                out = client.getOutputStream();

                MyRequest request = new MyRequest(input);
                request.parse();

                MyResponse response = new MyResponse(out);
                response.setRequest(request);
                response.sendMessage();

                client.close();

                shutdown = request.getUri().equals(SHUTDOWN_COMMAND);

            } catch (IOException e) {
                System.out.println(">>>>>>>>>關閉Socket異常<<<<<<<<<<");
                System.out.println(e.getMessage());
                System.out.println(">>>>>>>>>>>>>><<<<<<<<<<<<<<<<<");

            }
        }

    }
}
//
package com.wuhulala.chap1;

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

/**
 * 請求類,用於格式化請求報文
 * 
 * @author xueaohui
 * @version 1.0
 * @date 2017/2/19
 */
public class MyRequest {
    private InputStream input;
    private String uri;

    public MyRequest(InputStream input) {
        this.input = input;
    }

    /**
     * 解析報文
     */
    public void parse() {
        StringBuffer request = new StringBuffer(2048);

        int i = 0;
        byte[] buffer = new byte[2048];

        try {
            i = input.read(buffer);
        } catch (IOException e) {
            System.out.println(">>>>>>>>>>>>>>解析HTTP協議錯誤<<<<<<<<<<<<<<<");
            System.out.println(e.getMessage());
        }

        for (int j = 0; j < i; j++) {
            request.append((char)buffer[j]);
        }
        System.out.println(">>>>>>>>>>>>>>解析HTTP協議結果<<<<<<<<<<<<<<<");
        System.out.println(request.toString());
        System.out.println(">>>>>>>>>>>>>>解析HTTP協議結果<<<<<<<<<<<<<<<");
        parseURI(request.toString());
    }

    /**
     * 通過請求解析URI
     *
     * @param request 請求字串
     */
    private void parseURI(String request) {
        int index1, index2;
        index1 = request.indexOf(' ');
        if (index1 != -1) {
            index2 = request.indexOf(' ', index1 + 1);
            if(index2 > index1){
                uri = request.substring(index1+1,index2);
            }else{
                uri = "error";
            }
        }else{
            uri = "error";
        }
    }

    public String getUri() {
        return uri;
    }
}
package com.wuhulala.chap1;

import java.io.IOException;
import java.io.OutputStream;

/**
 * 響應類 用於輸出響應報文
 *
 * @author xueaohui
 * @version 1.0
 * @date 2017/2/19
 */
public class MyResponse {
    private OutputStream out;
    private MyRequest request;

    public MyResponse(OutputStream out) {
        this.out = out;
    }

    public void setRequest(MyRequest request) {
        this.request = request;
    }


    public void sendMessage() throws IOException {

        String message = "HTTP/1.1 200 OK \r\n" +
                "content-type:text/html\r\n" +
                "\r\n" +
                "<h1>Hello "+request.getUri()+"!</h1>" +
                "<h2>shutdown_command:/shutdown</h2>";

        out.write(message.getBytes());

    }
}

3. 總結

此例通過socket實現接受http請求。解析了tomcat接受請求的原理。那麼我現在聯想到了Tomcat通過NIO連線的本質。。。不知道爾等想到了嗎

相關文章