Tomcat 服務器是一個免費的開放源代碼的Web 應用服務器,屬於輕量級應用服務器,在中小型系統和併發訪問用戶不是不少的場合下被廣泛使用,是開發和調試JSP 程序的首選。今天就來爲你們介紹一下關於Tomcat的詳細內容。html
聲明:
1:本系列僅記錄本人讀<<深刻剖析Tomcat>>此書的一些感悟,不足之處,留言指正,不勝感激。2:本系列全部代碼參照<<深刻剖析Tomcat>>,不對之處,留言指正,不勝感激。
概念:傳送門:tomcat百度百科,這裏說一個點,tomcat是輕量級的javaweb服務器,用於處理servlet/jsp等動態網頁,雖然說也能夠處理靜態網頁,但相比apache而言仍是遜色很多。有興趣的朋友能夠另行了解一下 nginx, iis,apache等其餘較爲流行的web服務器。
使用過tomcat的朋友應該知道,當java web項目部署到tomcat後,在瀏覽器地址欄裏輸入:http://localhost:8080/資源路徑,即可以訪問項目資源。在這一過程當中,tomcat扮演調度中心的角色,接收瀏覽器發起資源請求並解析,根據解析結果分發給指定web項目處理,而後根據處理結果,對瀏覽器響應。對此,咱們來研究一下,tomcat是怎麼作到的。
項目結構:java
MyTomcat
接收請求(Request)
想接收瀏覽發起的請求,須要作幾手準備, 1:監聽端口(8080), 2:接收瀏覽器鏈接(socket鏈接) 3:解析HTTP請求數據。下面是代碼模擬:nginx
第一第二步: 使用httpServer模擬tomcat調度中心 /** * 模擬tomcat的核心類 */public class HttpServer { //tomcat項目絕對路徑, 全部web項目都丟在webapps目錄下 public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webapps"; // 模擬tomcat關閉命令 private static final String SHUTDOWN_CMD = "/SHUTDOWN"; private boolean shutdown = false; //持續監聽端口 @SuppressWarnings("resource") public void accept() { ServerSocket serverSocket = null; try { // 啓動socket服務, 監聽8080端口, serverSocket = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("啓動myTomcat服務器失敗:" + e.getMessage(), e); } // 沒接收到關閉命令前一直監聽 while (!shutdown) { Socket socket = null; InputStream in = null; OutputStream out = null; try { // 接收請求 socket = serverSocket.accept(); in = socket.getInputStream(); out = socket.getOutputStream(); // 將瀏覽器發送的請求信息封裝成請求對象 Request request = new Request(in); request.parseRequest(); // 將相應信息封裝相應對象 //此處簡單響應一個靜態資源文件 Response response = new Response(out); //模擬頁面跳轉 response.sendRedircet(request.getUri()); socket.close(); //若是是使用關閉命令,中止監聽退出 shutdown = request.getUri().equals(SHUTDOWN_CMD); } catch (Exception e) { e.printStackTrace(); continue; } } } public static void main(String[] args) { new HttpServer().accept(); } } 第三步,使用HttpReqeust封裝請求相關信息 /** * 請求信息封裝對象 */public class Request { // 瀏覽器socket鏈接的讀流 private InputStream in; //請求行信息信息中的uri private String uri; public Request(InputStream in) { this.in = in; } // 解析瀏覽器發起的請求 public void parseRequest() { // 暫時忽略文件上傳的請求,假設都字符型請求 byte[] buff = new byte[2048]; StringBuffer sb = new StringBuffer(2048); int len = 0; //請求內容 try { len = in.read(buff); sb.append(new String(buff, 0, len)); } catch (IOException e) { e.printStackTrace(); } System.out.print(sb.toString()); //解析請求行中uri信息 uri = this.parseUri(sb.toString()); } /**tomcat接收瀏覽器發起的請求是居於http協議的,請求內容格式:*/ /**請求行:請求方式 請求uri 協議版本*/ //GET /index HTTP/1.1 /**請求頭:以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: ..... /**請求體: 請求頭回車格一行就是請求體,get方式請求體爲空*/ public String parseUri(String httpContent) { //傳入的內容解析第一行的請求行便可: //請求行格式: 請求方式 請求uri 協議版本 3個內容以空格隔開 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; } } 假設,瀏覽器發起請求:http://localhost:8080/hello/index.html HttpServer中socket經過輸入流獲取到的數據是: 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 將上述的數據交於HttpRequest對象處理,該對象調用parseRequest解析,獲取請求行中的uri 數據, 分析該數據, 獲得上下文路徑,項目名,資源名。統稱資源路徑。 上面數據獲得: hello 項目下, index.html 資源(沒有上下文路徑) 響應請求 當從請求信息中獲取uri後,進而獲取到hello 項目, index.html資源, 響應請求就能夠簡單認爲根據資源路徑查找資源,若是找到,使用socket output流直接輸出資源數據便可,若是找不到,輸出404信息。 * 處理響應請求對象 public class Response { // 瀏覽器socket鏈接的寫流 private OutputStream out; public Response(OutputStream out) { this.out = out; } public OutputStream getOutputStream() { return out; } //跳轉 public void sendRedircet(String uri) { File webPage = new File(HttpServer.WEB_ROOT, uri); FileInputStream fis = null; StringBuffer sb = new StringBuffer(); try { //找獲得頁面是 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 { //頁面找不到時 String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + "File Not Found"; out.write(errorMessage.getBytes()); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (fis != null) { fis.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
此處注意, 響應請求數據也必須遵循http協議。
對於Tomcat,還有不少內容須要研究,若是你們對此感興趣的話,不妨和咱們一塊兒,繼續探索。如今就關注咱們,咱們繼續深刻探索Tomcat。web