国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

tomcat實現(xiàn)原理(一)

2019-11-06 06:17:40
字體:
供稿:網(wǎng)友

一 概述

       前段時間去面試,被人問到了tomcat實現(xiàn)原理。由于平時沒怎么關注容器的實現(xiàn)細節(jié),這個問題基本沒回答上來。所以最近花了很多時間一直在網(wǎng)上找資料和看tomcat的源碼來研究里面處理一個HTTP請求的流程。網(wǎng)上講tomcat的帖子比較多,大多都是直接切入主題看其源碼,從我個人感受來說直接研究其源碼實現(xiàn)比較難理解和非常枯燥,需要由簡到難,慢慢深入。

二  一個簡單tomcat服務器實現(xiàn)

        tomat是一個servlet容器,來處理http請求。在平時的使用中我們都會再瀏覽器中輸入http地址來訪問服務資源,比如格式http://host[":"port][abs_path]。從瀏覽器到服務端的一次請求都遵循h(huán)ttp協(xié)議,在網(wǎng)絡上其實走仍然是tcp協(xié)議,即我們常使用的socket來處理客戶端和服務器的交互。根據(jù)輸入的http地址可以知道服務器的ip地址和端口,根據(jù)這兩個參數(shù)就可以定位到服務器的唯一地址。tomcat根據(jù)http地址端口后面的資源路徑就可以知道反饋什么樣的資源給瀏覽器。下面給出了一個非常簡單的代碼模擬了tomcat的簡單實現(xiàn)

package com;import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.net.URLDecoder;import java.util.StringTokenizer;public class TomcatServer {    PRivate final static int PORT = 8080;    public static void main(String[] args) {        try {            ServerSocket server = new ServerSocket(PORT);//根據(jù)端口號啟動一個serverSocket            ServletHandler servletHandler=new ServletHandler(server);            servletHandler.start();        } catch (Exception e) {            e.printStackTrace();        }    }    private static class ServletHandler extends Thread{        ServerSocket server=null;        public ServletHandler(ServerSocket server){            this.server=server;        }        @Override        public void run() {            while (true) {                try {                    Socket client = null;                    client = server.accept();//ServerSocket阻塞等待客戶端請求數(shù)據(jù)                    if (client != null) {                        try {                            System.out.println("接收到一個客戶端的請求");                            //根據(jù)客戶端的Socket對象獲取輸入流對象。                            //封裝字節(jié)流到字符流                            BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));                            // GET /test.jpg /HTTP1.1                            //http請求由三部分組成,分別是:請求行、消息報頭、請求正文。                            //這里取的第一行數(shù)據(jù)就是請求行。http協(xié)議詳解可以參考http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html說的很詳細                            String line = reader.readLine();                            System.out.println("line: " + line);                            //拆分http請求路徑,取http需要請求的資源完整路徑                            String resource = line.substring(line.indexOf('/'),line.lastIndexOf('/') - 5);                            System.out.println("the resource you request is: "+ resource);                            resource = URLDecoder.decode(resource, "UTF-8");                            //獲取到這次請求的方法類型,比如get或post請求                            String method = new StringTokenizer(line).nextElement().toString();                            System.out.println("the request method you send is: "+ method);                            //繼續(xù)循環(huán)讀取瀏覽器客戶端發(fā)出的一行一行的數(shù)據(jù)                            while ((line = reader.readLine()) != null) {                                if (line.equals("")) {//當line等于空行的時候標志Header消息結(jié)束                                    break;                                }                                System.out.println("the Http Header is : " + line);                            }                            //如果是POST的請求,直接打印POST提交上來的數(shù)據(jù)                            if ("post".equals(method.toLowerCase())) {                                System.out.println("the post request body is: "                                        + reader.readLine());                            }else if("get".equals(method.toLowerCase())){                                //判斷是get類型的http請求處理                                //根據(jù)http請求的資源后綴名來確定返回數(shù)據(jù)                                //比如下載一個圖片文件,我這里直接給定一個圖片路徑來模擬下載的情況                                if (resource.endsWith(".jpg")) {                                    transferFileHandle("d://123.jpg", client);                                    closeSocket(client);                                    continue;                                } else {                             //直接返回一個網(wǎng)頁數(shù)據(jù)                             //其實就是將html的代碼以字節(jié)流的形式寫到IO中反饋給客戶端瀏覽器。                             //瀏覽器會根據(jù)http報文“Content-Type”來知道反饋給瀏覽器的數(shù)據(jù)是什么格式的,并進行什么樣的處理                             PrintStream writer = new PrintStream(client.getOutputStream(), true);                             writer.println("HTTP/1.0 200 OK");// 返回應答消息,并結(jié)束應答                             writer.println("Content-Type:text/html;charset=utf-8");                             writer.println();                             //writer.println("Content-Length:" + html.getBytes().length);// 返回內(nèi)容字節(jié)數(shù)                             writer.println("<html><body>");                             writer.println("<a href='www.baidu.com'>百度</a>");                             writer.println("<img src='https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png'></img>");                             writer.println("</html></body>");                             //writer.println("HTTP/1.0 404 Not found");// 返回應答消息,并結(jié)束應答                             writer.println();// 根據(jù) HTTP 協(xié)議, 空行將結(jié)束頭信息                             writer.close();                             closeSocket(client);//請求資源處理完畢,關閉socket鏈接                             continue;                                }                            }                        } catch (Exception e) {                            System.out.println("HTTP服務器錯誤:"                                    + e.getLocalizedMessage());                        }                    }                } catch (Exception e) {                    e.printStackTrace();                }            }        }        private void closeSocket(Socket socket) {            try {                socket.close();            } catch (IOException ex) {                ex.printStackTrace();            }            System.out.println(socket + "離開了HTTP服務器");        }        private void transferFileHandle(String path, Socket client) {            File fileToSend = new File(path);            if (fileToSend.exists() && !fileToSend.isDirectory()) {                try {                    //根據(jù)Socket獲取輸出流對象,將訪問的資源數(shù)據(jù)寫入到輸出流中                    PrintStream writer = new PrintStream(client.getOutputStream());                    writer.println("HTTP/1.0 200 OK");// 返回應答消息,并結(jié)束應答                    writer.println("Content-Type:application/binary");                    writer.println("Content-Length:" + fileToSend.length());// 返回內(nèi)容字節(jié)數(shù)                    writer.println();// 根據(jù) HTTP 協(xié)議, 空行將結(jié)束頭信息                    FileInputStream fis = new FileInputStream(fileToSend);                    byte[] buf = new byte[fis.available()];                    fis.read(buf);                    writer.write(buf);                    writer.close();                    fis.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }}

三  實踐

    1.在瀏覽器中輸入http://localhost:8080/123.jpg 鏈接,可以看到瀏覽器里面就將123.jpg下載到本地了。

    2.在瀏覽器中輸入一個服務器不能識別的請求后綴比如http://localhost:8080/123.jpg1,可以看到瀏覽器打開了一個網(wǎng)頁。如下圖:點擊里面的百度鏈接可以跳轉(zhuǎn)

    3.后臺tomcat服務器打印的http請求報文

       接收到一個客戶端的請求line: GET /123.jpg1 HTTP/1.1the resource you request is: /123.jpg1the request method you send is: GETthe Http Header is : Host: localhost:8080the Http Header is : Connection: keep-alivethe Http Header is : Pragma: no-cachethe Http Header is : Cache-Control: no-cachethe Http Header is : Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8the Http Header is : Upgrade-Insecure-Requests: 1the Http Header is : User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36the Http Header is : Accept-Encoding: gzip, deflate, sdchthe Http Header is : Accept-Language: zh-CN,zh;q=0.8Socket[addr=/0:0:0:0:0:0:0:1,port=57864,localport=8080]離開了HTTP服務器

四  總結(jié)

    從整個代碼和測試情況來看,一次http請求其實就是一次socket套接字的處理。瀏覽器發(fā)起scoket的請求,tomcat服務器接受請求,并根據(jù)請求的路徑定位客戶端需要訪問的資源。  只是socket客戶端和服務器數(shù)據(jù)在交互時,都遵守著http協(xié)議規(guī)范。當然真正的tomcat容器比這個demo實現(xiàn)要復雜的很多,這個簡易的tomcat服務器能夠幫我們更好的理解tomcat源碼。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 汉中市| 阳山县| 简阳市| 禄丰县| 固镇县| 如东县| 香格里拉县| 天台县| 宣汉县| 汉川市| 太谷县| 衡阳县| 高尔夫| 万安县| 米易县| 陕西省| 万宁市| 峨眉山市| 伊川县| 莱芜市| 垦利县| 繁昌县| 孟村| 仁化县| 云霄县| 尚义县| 荆州市| 吴江市| 大竹县| 江川县| 井陉县| 全南县| 若尔盖县| 三原县| 商南县| 南靖县| 甘德县| 绥芬河市| 东兰县| 扶沟县| 高要市|