生活随笔
收集整理的這篇文章主要介紹了
tomcat原理解析(一):一个简单的实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一 概述 ? ? ? ?前段時間去面試,被人問到了tomcat實現原理。由于平時沒怎么關注容器的實現細節,這個問題基本沒回答上來。所以最近花了很多時間一直在網上找資料和看tomcat的源碼來研究里面處理一個HTTP請求的流程。網上講tomcat的帖子比較多,大多都是直接切入主題看其源碼,從我個人感受來說直接研究其源碼實現比較難理解和非常枯燥,需要由簡到難,慢慢深入。
二 ?一個簡單tomcat服務器實現 ? ? ? ??tomat是一個servlet容器,來處理http請求。在平時的使用中我們都會再瀏覽器中輸入http地址來訪問服務資源,比如格式http://host[":"port][abs_path]。從瀏覽器到服務端的一次請求都遵循http協議,在網絡上其實走仍然是tcp協議,即我們常使用的socket來處理客戶端和服務器的交互。根據輸入的http地址可以知道服務器的IP地址和端口,根據這兩個參數就可以定位到服務器的唯一地址。tomcat根據http地址端口后面的資源路徑就可以知道反饋什么樣的資源給瀏覽器。下面給出了一個非常簡單的代碼模擬了tomcat的簡單實現
?
[html] ?view plaincopy
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);//根據端口號啟動一個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阻塞等待客戶端請求數據?? ????????????????????if?(client?!=?null)?{?? ????????????????????????try?{?? ????????????????????????????System.out.println("接收到一個客戶端的請求");?? ?? ????????????????????????????//根據客戶端的Socket對象獲取輸入流對象。?? ????????????????????????????//封裝字節流到字符流?? ????????????????????????????BufferedReader?reader?=?new?BufferedReader(new?InputStreamReader(client.getInputStream()));?? ?? ????????????????????????????//?GET?/test.jpg?/HTTP1.1?? ????????????????????????????//http請求由三部分組成,分別是:請求行、消息報頭、請求正文。?? ????????????????????????????//這里取的第一行數據就是請求行。http協議詳解可以參考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);?? ?? ????????????????????????????//繼續循環讀取瀏覽器客戶端發出的一行一行的數據?? ????????????????????????????while?((line?=?reader.readLine())?!=?null)?{?? ????????????????????????????????if?(line.equals(""))?{//當line等于空行的時候標志Header消息結束?? ????????????????????????????????????break;?? ????????????????????????????????}?? ????????????????????????????????System.out.println("the?Http?Header?is?:?"?+?line);?? ????????????????????????????}?? ?? ????????????????????????????//如果是POST的請求,直接打印POST提交上來的數據?? ????????????????????????????if?("post".equals(method.toLowerCase()))?{?? ????????????????????????????????System.out.println("the?post?request?body?is:?"?? ????????????????????????????????????????+?reader.readLine());?? ????????????????????????????}else?if("get".equals(method.toLowerCase())){?? ????????????????????????????????//判斷是get類型的http請求處理?? ????????????????????????????????//根據http請求的資源后綴名來確定返回數據?? ?? ????????????????????????????????//比如下載一個圖片文件,我這里直接給定一個圖片路徑來模擬下載的情況?? ????????????????????????????????if?(resource.endsWith(".jpg"))?{?? ????????????????????????????????????transferFileHandle("d://123.jpg",?client);?? ????????????????????????????????????closeSocket(client);?? ????????????????????????????????????continue;?? ?? ????????????????????????????????}?else?{?? ?? ?????????????????????????????//直接返回一個網頁數據?? ?????????????????????????????//其實就是將html的代碼以字節流的形式寫到IO中反饋給客戶端瀏覽器。?? ?????????????????????????????//瀏覽器會根據http報文“Content-Type”來知道反饋給瀏覽器的數據是什么格式的,并進行什么樣的處理?? ?? ?????????????????????????????PrintStream?writer?=?new?PrintStream(client.getOutputStream(),?true);?? ?????????????????????????????writer.println("HTTP/1.0?200?OK");//?返回應答消息,并結束應答?? ?????????????????????????????writer.println("Content-Type:text/html;charset=utf-8");?? ?????????????????????????????writer.println();?? ?????????????????????????????//writer.println("Content-Length:"?+?html.getBytes().length);//?返回內容字節數?? ?????????????????????????????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");//?返回應答消息,并結束應答?? ?????????????????????????????writer.println();//?根據?HTTP?協議,?空行將結束頭信息?? ?????????????????????????????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?{?? ????????????????????//根據Socket獲取輸出流對象,將訪問的資源數據寫入到輸出流中?? ????????????????????PrintStream?writer?=?new?PrintStream(client.getOutputStream());?? ????????????????????writer.println("HTTP/1.0?200?OK");//?返回應答消息,并結束應答?? ????????????????????writer.println("Content-Type:application/binary");?? ????????????????????writer.println("Content-Length:"?+?fileToSend.length());//?返回內容字節數?? ????????????????????writer.println();//?根據?HTTP?協議,?空行將結束頭信息?? ?? ????????????????????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,可以看到瀏覽器打開了一個網頁。如下圖:點擊里面的百度鏈接可以跳轉
? ? 3.后臺tomcat服務器打印的http請求報文
?
? ? ??接收到一個客戶端的請求 line: GET /123.jpg1 HTTP/1.1 the resource you request is: /123.jpg1 the request method you send is: GET the Http Header is : Host: localhost:8080 the Http Header is : Connection: keep-alive the Http Header is : Pragma: no-cache the Http Header is : Cache-Control: no-cache the Http Header is : Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 the Http Header is : Upgrade-Insecure-Requests: 1 the 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.36 the Http Header is : Accept-Encoding: gzip, deflate, sdch the Http Header is : Accept-Language: zh-CN,zh;q=0.8 Socket[addr=/0:0:0:0:0:0:0:1,port=57864,localport=8080]離開了HTTP服務器
四 ?總結 從整個代碼和測試情況來看,一次http請求其實就是一次socket套接字的處理。瀏覽器發起scoket的請求,tomcat服務器接受請求,并根據請求的路徑定位客戶端需要訪問的資源。 ?只是socket客戶端和服務器數據在交互時,都遵守著http協議規范。當然真正的tomcat容器比這個demo實現要復雜的很多,這個簡易的tomcat服務器能夠幫我們更好的理解tomcat源碼。
轉載于:https://www.cnblogs.com/csguo/p/7499395.html
總結
以上是生活随笔 為你收集整理的tomcat原理解析(一):一个简单的实现 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。