溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

探索免費(fèi)開源服務(wù)器tomcat的魅力

發(fā)布時(shí)間:2020-02-24 13:07:29 來(lái)源:網(wǎng)絡(luò) 閱讀:173 作者:qq593e097eaab3c 欄目:數(shù)據(jù)庫(kù)

Tomcat最初是由Sun的軟件架構(gòu)師詹姆斯·鄧肯·戴維森開發(fā)的。后來(lái)他幫助將其變?yōu)殚_源項(xiàng)目,并由Sun貢獻(xiàn)給Apache軟件基金會(huì),并且成為Jakarta 項(xiàng)目中的一個(gè)核心項(xiàng)目。因此逐漸成為世界上廣泛使用的支持jsp和servlets的Web服務(wù)器。

探索免費(fèi)開源服務(wù)器tomcat的魅力
聲明:
1:本系列僅記錄本人讀<<深入剖析Tomcat>>此書的一些感悟,不足之處,留言指正,不勝感激。2:本系列所有代碼參照<<深入剖析Tomcat>>,不對(duì)之處,留言指正,不勝感激。
概念:傳送門:tomcat百度百科,這里說(shuō)一個(gè)點(diǎn),tomcat是輕量級(jí)的javaweb服務(wù)器,用于處理servlet/jsp等動(dòng)態(tài)網(wǎng)頁(yè),雖說(shuō)也可以處理靜態(tài)網(wǎng)頁(yè),但相比apache而言還是遜色不少。有興趣的朋友可以另行了解一下 nginx, iis,apache等其他較為流行的web服務(wù)器。
使用過(guò)tomcat的朋友應(yīng)該知道,當(dāng)java web項(xiàng)目部署到tomcat后,在瀏覽器地址欄里輸入:http://localhost:8080/資源路徑,便可以訪問(wèn)項(xiàng)目資源。在這一過(guò)程中,tomcat扮演調(diào)度中心的角色,接收瀏覽器發(fā)起資源請(qǐng)求并解析,根據(jù)解析結(jié)果分發(fā)給指定web項(xiàng)目處理,然后根據(jù)處理結(jié)果,對(duì)瀏覽器響應(yīng)。對(duì)此,我們來(lái)研究一下,tomcat是怎么做到的。
項(xiàng)目結(jié)構(gòu):

MyTomcat
接收請(qǐng)求(Request)
想接收瀏覽發(fā)起的請(qǐng)求,需要做幾手準(zhǔn)備, 1:監(jiān)聽端口(8080), 2:接收瀏覽器連接(socket連接) 3:解析HTTP請(qǐng)求數(shù)據(jù)。下面是代碼模擬:

第一第二步: 使用httpServer模擬tomcat調(diào)度中心
/**
 * 模擬tomcat的核心類
 */public class HttpServer {
    //tomcat項(xiàng)目絕對(duì)路徑, 所有web項(xiàng)目都丟在webapps目錄下
    public static final String WEB_ROOT =
            System.getProperty("user.dir") + File.separator  + "webapps";
    // 模擬tomcat關(guān)閉命令
    private static final String SHUTDOWN_CMD = "/SHUTDOWN";
    private boolean shutdown = false;
    //持續(xù)監(jiān)聽端口
    @SuppressWarnings("resource")
    public void accept() {
        ServerSocket serverSocket = null;
        try {
            // 啟動(dòng)socket服務(wù), 監(jiān)聽8080端口,
            serverSocket =  new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("啟動(dòng)myTomcat服務(wù)器失?。? + e.getMessage(), e);
        }
        // 沒(méi)接收到關(guān)閉命令前一直監(jiān)聽
        while (!shutdown) {
            Socket socket = null;
            InputStream in = null;
            OutputStream out = null;
            try {
                // 接收請(qǐng)求
                socket = serverSocket.accept();
                in = socket.getInputStream();
                out = socket.getOutputStream();
                // 將瀏覽器發(fā)送的請(qǐng)求信息封裝成請(qǐng)求對(duì)象
                Request request = new Request(in);
                request.parseRequest();
                // 將相應(yīng)信息封裝相應(yīng)對(duì)象
                //此處簡(jiǎn)單響應(yīng)一個(gè)靜態(tài)資源文件
                Response response = new Response(out);
                //模擬頁(yè)面跳轉(zhuǎn)
                response.sendRedircet(request.getUri());
                socket.close();
                //如果是使用關(guān)閉命令,停止監(jiān)聽退出
                shutdown = request.getUri().equals(SHUTDOWN_CMD);
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
    }
    public static void main(String[] args) {
        new HttpServer().accept();
    }
}
第三步,使用HttpReqeust封裝請(qǐng)求相關(guān)信息
/**
 * 請(qǐng)求信息封裝對(duì)象
 */public class Request {
    // 瀏覽器socket連接的讀流
    private InputStream in;
    //請(qǐng)求行信息信息中的uri
    private String uri;
    public Request(InputStream in) {
        this.in = in;
    }
    // 解析瀏覽器發(fā)起的請(qǐng)求
    public void parseRequest() {
        // 暫時(shí)忽略文件上傳的請(qǐng)求,假設(shè)都字符型請(qǐng)求
        byte[] buff = new byte[2048];
        StringBuffer sb = new StringBuffer(2048);
        int len = 0;
        //請(qǐng)求內(nèi)容
        try {
            len = in.read(buff);
            sb.append(new String(buff, 0, len));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.print(sb.toString());
        //解析請(qǐng)求行中uri信息
        uri = this.parseUri(sb.toString());
    }

    /**tomcat接收瀏覽器發(fā)起的請(qǐng)求是居于http協(xié)議的,請(qǐng)求內(nèi)容格式:*/
    /**請(qǐng)求行:請(qǐng)求方式   請(qǐng)求uri 協(xié)議版本*/
    //GET /index HTTP/1.1    
    /**請(qǐng)求頭:以key-value形式存在*/
    //Host: localhost:8080
    //Connection: keep-alive
    //Upgrade-Insecure-Requests: 1
    //User-Agent: Mozilla/5.0 .........
    //Accept: text/html,application/xhtml+xml......
    //Accept-Encoding: gzip, deflate, br
    //Accept-Language: zh-CN,zh;q=0.9
    //Cookie: .....
    /**請(qǐng)求體: 請(qǐng)求頭回車格一行就是請(qǐng)求體,get方式請(qǐng)求體為空*/
    public String parseUri(String httpContent) {
        //傳入的內(nèi)容解析第一行的請(qǐng)求行即可:
        //請(qǐng)求行格式:  請(qǐng)求方式   請(qǐng)求uri 協(xié)議版本     3個(gè)內(nèi)容以空格隔開
        int beginIndex = httpContent.indexOf(" ");
        int endIndex;
        if(beginIndex > -1) {
            endIndex = httpContent.indexOf(" ", beginIndex + 1);
            if(endIndex > beginIndex) {
                return httpContent.substring(beginIndex, endIndex).trim();
            }
        }
        return null;
    }

    public String getUri() {
        return uri;
    }
}
假設(shè),瀏覽器發(fā)起請(qǐng)求:http://localhost:8080/hello/index.html HttpServer中socket通過(guò)輸入流獲取到的數(shù)據(jù)是:
GET /hello/index.html HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: Hm_lvt_aa5c701f4f646931bf78b6f40b234ef5=1516445118,1516604544,1518416964,1518497222; JSESSIONID=79367FD9A55B9B442C4ED112D10FDAC5
HttpServer 將上述的數(shù)據(jù)交于HttpRequest對(duì)象處理,該對(duì)象調(diào)用parseRequest解析,獲取請(qǐng)求行中的uri 數(shù)據(jù), 分析該數(shù)據(jù), 得到上下文路徑,項(xiàng)目名,資源名。統(tǒng)稱資源路徑。
上面數(shù)據(jù)得到: hello 項(xiàng)目下, index.html 資源(沒(méi)有上下文路徑)
響應(yīng)請(qǐng)求
當(dāng)從請(qǐng)求信息中獲取uri后,進(jìn)而獲取到hello 項(xiàng)目, index.html資源, 響應(yīng)請(qǐng)求就可以簡(jiǎn)單認(rèn)為根據(jù)資源路徑查找資源,如果找到,使用socket output流直接輸出資源數(shù)據(jù)即可,如果找不到,輸出404信息。

 * 處理響應(yīng)請(qǐng)求對(duì)象
public class Response {
    // 瀏覽器socket連接的寫流
    private OutputStream out;

    public Response(OutputStream out) {
        this.out = out;
    }
    public OutputStream getOutputStream() {
        return out;
    }
    //跳轉(zhuǎn)
    public void sendRedircet(String uri) {

        File webPage = new File(HttpServer.WEB_ROOT, uri);
        FileInputStream fis = null;
        StringBuffer sb = new StringBuffer();
        try {
            //找得到頁(yè)面是
            if(webPage.exists()&& webPage.isFile()) {
                String respHeader = "HTTP/1.1 200 OK\r\n" +
                  "Content-Type: text/html\r\n" +
                  "Content-Length: #{count}\r\n" +
                  "\r\n";
                fis = new FileInputStream(webPage);
                byte[] buff = new byte[2048];
                int len = 0;
                while( (len = fis.read(buff))!= -1) {
                    sb.append(new String(buff, 0, len));
                }
                respHeader=respHeader.replace("#{count}", sb.length()+"");
                System.out.println(respHeader + sb);
                out.write((respHeader + sb).getBytes());

            }else {
                 //頁(yè)面找不到時(shí)
                String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
                  "Content-Type: text/html\r\n" +
                  "Content-Length: 23\r\n" +
                  "\r\n" +
                  "<h2>File Not Found</h2>";
                out.write(errorMessage.getBytes());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

此處注意, 響應(yīng)請(qǐng)求數(shù)據(jù)也必須遵循h(huán)ttp協(xié)議。
這些內(nèi)容只是我在<<深入剖析Tomcat>>一書中的一些理解,這些也只是Tomcat中的一部分,如果其中有什么問(wèn)題,還請(qǐng)大家指出,當(dāng)然有需要幫助的,我也會(huì)盡力幫助大家。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI