生活随笔
收集整理的這篇文章主要介紹了
深入学习Tomcat----自己动手写服务器(附服务器源码)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
相信大多Web開發者對Tomcat是非常熟悉的,眾所周知Tomcat是一款非常好用的開源Servlet容器,您一定對這個最流行的Servlet容器充滿好奇,雖然它并不像一個黑盒子那樣讓人無法觸摸但是Tomcat的源碼的確讓人看起來頭疼。筆者就在這里和大家共同分析一個簡單的Web服務器是如何工作的源碼下載地址。
Web服務器
Web服務器是一個復雜的系統,一個Web服務器要為一個Servlet的請求提供服務,需要做三件事:
1、創建一個request對象并填充那些有可能被所引用的Servlet使用的信息,如參數、頭部、cookies、查詢字符串等等。一個request對象是javax.servlet.ServletRequest或javax.servlet.http.ServletRequest接口的一個實例
2、創建一個response對象,所引用的servlet使用它來給客戶端發送響應。一個response對象是javax.servlet.ServletRequest或javax.servlet.http.ServletRequest接口的一個實例。
3、調用servlet的service方法,并傳入request和response對象。這里servlet會從request對象取值,給response寫值。
在正式展示代碼之前還需要了解一些必須額HTTP的知識(如果您對此非常熟悉您可以直接看下面分析代碼)
HTTP
HTTP的定義不知道的童鞋可以自己去度娘,這里主要要說的就是HTTP協議的格式
HTTP請求包括三部分
1、方法、統一資源標識符(URI)、協議/版本
2、請求的頭部
3、主題內容
下面是一個HTTP請求的例子
POST?/examples/default.jsp?HTTP/1.1???Accept:?text/plain;?text/html???Accept-Language:?en-gb???Connection:?Keep-Alive???Host:?localhost???User-Agent:?Mozilla/4.0?(compatible;?MSIE?4.01;?Windows?98)???Content-Length:?33???Content-Type:?application/x-www-form-urlencoded???Accept-Encoding:?gzip,?deflate??????lastName=Franks&firstName=Michael???? 第一行表明這是POST請求方法,/examples/default.jsp是URI,HTTP/1.1是協議以及版本。其中URI指明了一個互聯網資源,這里通常是相對服務器根目錄解釋的,也就是說這個HTTP請求就是告訴服務器我需要這個文件目錄如下:根目錄/ examples/default.jsp。
最后一行是HTTP的主題內容,Servlet會處理請求的主題內容,然后返回給客戶端HTTP響應。
類似于HTTP請求,一個HTTP響應也包括上面三個部分。
1、方法、統一資源標識符(URI)、協議/版本
2、響應的頭部
3、主題內容
下面是一個HTTP響應的例子
HTTP/1.1?200?OK???Server:?Microsoft-IIS/4.0???Date:?Mon,?5?Jan?2004?13:13:33?GMT???Content-Type:?text/html???Last-Modified:?Mon,?5?Jan?2004?13:13:12?GMT???Content-Length:?112??????<html>???<head>???<title>HTTP?Response?Example</title>???</head>???<body>???Welcome?to?Brainy?Software???</body>???</html>?? 第一行告訴協議版本,以及請求成功(200表示成功)
響應頭部和請求頭部一樣,一些有用的信息。響應的主體就是響應本身HTML內容。
好了基本知識介紹完畢,下面開始解釋代碼
部分相關代碼
import?java.net.Socket;??import?java.net.ServerSocket;??import?java.net.InetAddress;??import?java.io.InputStream;??import?java.io.OutputStream;??import?java.io.IOException;??import?java.io.File;????public?class?HttpServer?{????????public?static?final?String?WEB_ROOT?=?System.getProperty("user.dir")??????????????+?File.separator?+?"webroot";????????private?static?final?String?SHUTDOWN_COMMAND?=?"/SHUTDOWN";????????private?boolean?shutdown?=?false;????????public?static?void?main(String[]?args)?{??????????HttpServer?server?=?new?HttpServer();??????????server.await();??????}????????public?void?await()?{??????????ServerSocket?serverSocket?=?null;??????????int?port?=?8080;??????????try?{??????????????serverSocket?=?new?ServerSocket(port,?1,??????????????????????InetAddress.getByName("127.0.0.1"));??????????}?catch?(IOException?e)?{??????????????e.printStackTrace();??????????????System.exit(1);??????????}????????????while?(!shutdown)?{??????????????Socket?socket?=?null;??????????????InputStream?input?=?null;??????????????OutputStream?output?=?null;??????????????try?{??????????????????socket?=?serverSocket.accept();??????????????????input?=?socket.getInputStream();??????????????????output?=?socket.getOutputStream();????????????????????Request?request?=?new?Request(input);??????????????????request.parse();????????????????????Response?response?=?new?Response(output);??????????????????response.setRequest(request);??????????????????response.sendStaticResource();????????????????????socket.close();????????????????????shutdown?=?request.getUri().equals(SHUTDOWN_COMMAND);??????????????}?catch?(Exception?e)?{??????????????????e.printStackTrace();??????????????????continue;??????????????}??????????}??????}??}?? HttpServer類代表一個web服務器。首先提供一個WEB_ROOT所在的目錄和它下面所有的子目錄下靜態資源。其次定義了一個中止服務的命令,也就是說當得到的請求后面跟/shutdown的時候停止服務,默認是把服務設置為開啟。下面就是進入main函數了,首先實例化一個HttpServer類,然后就是通過await方法等待客戶端發來的請求。如果客戶端輸入的URL不是http://localhost:8080/SHUTDOWN則表示不停止服務器,然后就是繼續執行await方法中的內容,在await方法中最重要的就是定義兩個對象,一個是request一個是response,下面就來說說Request和Response類。
import?java.io.InputStream;??import?java.io.IOException;????public?class?Request?{????????private?InputStream?input;??????private?String?uri;????????public?Request(InputStream?input)?{??????????this.input?=?input;??????}????????public?void?parse()?{????????????StringBuffer?request?=?new?StringBuffer(2048);??????????int?i;??????????byte[]?buffer?=?new?byte[2048];??????????try?{??????????????i?=?input.read(buffer);??????????}?catch?(IOException?e)?{??????????????e.printStackTrace();??????????????i?=?-1;??????????}??????????for?(int?j?=?0;?j?<?i;?j++)?{??????????????request.append((char)?buffer[j]);??????????}??????????System.out.print(request.toString());??????????uri?=?parseUri(request.toString());??????}????????private?String?parseUri(String?requestString)?{??????????int?index1,?index2;??????????index1?=?requestString.indexOf('?');??????????if?(index1?!=?-1)?{??????????????index2?=?requestString.indexOf('?',?index1?+?1);??????????????if?(index2?>?index1)??????????????????return?requestString.substring(index1?+?1,?index2);??????????}??????????return?null;??????}????????public?String?getUri()?{??????????return?uri;??????}????}?? 首先調用InputStream對象中的read方法獲取HTTP請求的原始數據,然后在parseUri方法中獲得uri也就是要請求的靜態資源。說白了Request類的主要作用就是告訴服務器用戶要的是什么也就是在http://localhost:8080后面出現的東西。
import?java.io.OutputStream;??import?java.io.IOException;??import?java.io.FileInputStream;??import?java.io.File;????public?class?Response?{????????private?static?final?int?BUFFER_SIZE?=?1024;??????Request?request;??????OutputStream?output;????????public?Response(OutputStream?output)?{??????????this.output?=?output;??????}????????public?void?setRequest(Request?request)?{??????????this.request?=?request;??????}????????public?void?sendStaticResource()?throws?IOException?{??????????byte[]?bytes?=?new?byte[BUFFER_SIZE];??????????FileInputStream?fis?=?null;??????????try?{??????????????File?file?=?new?File(HttpServer.WEB_ROOT,?request.getUri());??????????????if?(file.exists())?{??????????????????fis?=?new?FileInputStream(file);??????????????????int?ch?=?fis.read(bytes,?0,?BUFFER_SIZE);??????????????????while?(ch?!=?-1)?{??????????????????????output.write(bytes,?0,?ch);??????????????????????ch?=?fis.read(bytes,?0,?BUFFER_SIZE);??????????????????}??????????????}?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"??????????????????????????+?"<h1>File?Not?Found</h1>";??????????????????output.write(errorMessage.getBytes());??????????????}??????????}?catch?(Exception?e)?{????????????????????????????System.out.println(e.toString());??????????}?finally?{??????????????if?(fis?!=?null)??????????????????fis.close();??????????}??????}??}?? Response類代表一個HTTP響應。首先Response接收一個OutputStream對象,然后通過sendStaticResource方法對接收的Request進行處理,整個處理過程就是根據請求在服務器端進行尋找對應靜態資源的過程。找到所需要的資源后發送給客戶端然后讓客戶端顯示出來。
運行程序
運行上面的HttpServer類,然后在瀏覽器的地址欄中鍵入下面的地址:http:localhost:8080/index.jsp,然后你會在瀏覽器中看到index.jsp頁面。
在控制臺可以看到類似于下面的HTTP請求
GET?/index.jsp?HTTP/1.1??Host:?localhost:8080??Connection:?keep-alive??Cache-Control:?max-age=0??User-Agent:?Mozilla/5.0?(Windows?NT?6.1;?WOW64)?AppleWebKit/535.7?(KHTML,?like?Gecko)?Chrome/16.0.912.75?Safari/535.7?360EE??Accept:?text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8??Accept-Encoding:?gzip,deflate,sdch??Accept-Language:?zh-CN,zh;q=0.8??Accept-Charset:?GBK,utf-8;q=0.7,*;q=0.3?? 小結
上面自己動手寫的這個所謂的服務器僅僅有三個類組成,從功能上來說他只能顯示一些靜態的資源,并不是全部功能。一個優秀的服務器還有很多細節要做,但是出于學習的目的大家現在有這些了解就足夠了,后面還會有對服務器的詳細介紹,敬請期待。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的深入学习Tomcat----自己动手写服务器(附服务器源码)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。