前言:
有比較宏觀的問題,如下(持續更新中):
1.能否用一句話說明tomcat或者一個java web服務器做的事情?
2.http請求是怎麼進入tomcat服務器的,即內部的調用序列是怎麼樣的?
3.tomcat或者jboss如何和我們的web框架整合?
……
也有微觀的問題,如下(持續更新中):
1.http1.1的新特性是什麼?你又是否知道爲什麼會新添加這些新特性?
2. servlet實現了的singleTreadModel接口,就是線程安全的嗎?
3.你也許知道filter是幹嘛的,但是你知道filter是在哪裏、何時、被哪個模塊調用執行的嗎?
……
深入剖析tomcat讀書筆記1涉及1-3章,本身並不涉及tomcat的任何源碼。
第一章-----一個簡單的web服務器
介紹了簡單的實現web服務器的方法(對於靜態資源的處理,不涉及動態內容)。解析http報文得到請求的對象,處理請求對象得到結果,封裝結果返回相應對象。其實都是在用Java來實現一些字符串操作,通過字節流來承載內容。
Http協議
主要簡單介紹了http協議,更詳細地介紹在
http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html
http請求組成:請求行、請求頭、實體。
請求行:請求方法----URI----協議/版本
請求頭:Accept、Accept-Charset、Host、User-Agent、Content-Length、Content-Type
實體:各個請求參數
http響應組成:狀態行、響應報頭、響應正文
狀態行:協議—狀態碼—描述
響應報頭:Location、Server、Content-Length、Content-Type、Last-Modified
Socket類
Socket就是網絡連接的端點,有Socket和serverSocket兩種,前者爲客戶端建立,後者爲服務端建立。客戶端和服務端建立了socket鏈接,就可以進行通信。
socket通信是什麼?
我認爲本質上就是一邊輸入數據,一邊輸出數據。在java裏面,就是用封裝的字節流來處理。
如何通信?
發送數據方調用socket的getOutPutStream()方法,獲取OutputStream對象,用該OutputStream對象創建一個PrintWriter對象,調用PrintWriter的print()方法即可。接受數據方調用socket的getInputStream()方法,獲取InputStream對象,用該InputStream創建一個BufferReader,調用BufferReader的read()方法即可。
serverSocket
serverSocket是服務端創建的,要等待來自客戶端的請求。當serverSocket接收到了連接請求後,它會創建一個socket處理與客戶端的通信。就是調用serverSocket.accept()方法。
serverSocket構造函數中有一個backlog屬性,表示連接的隊列的長度(而不是連接的數量)。“輸入連接指示(對連接的請求)的最大隊列長度被設置爲 backlog 參數。如果隊列滿時收到連接指示,則拒絕該連接。”
第二章-----一個簡單的servlet容器
servlet容器主要可以處理動態內容。和Servlet技術並行的技術是cgi。和一個在騰訊工作的同學交流,騰訊web系統採用得就是cgi技術,後臺用C來實現。
Servlet是一套規範,要熟悉他,要參考在javax.servlet和java.servlet.http兩個包下的接口和類。最重要的接口就是servlet接口,有5個方法。
public void init(ServletConfig config)throws ServletException;
//當某個servlet被實例化後,servlet容器調用其init()方法進行初始化,比如設置數據庫鏈接、初始化默認值等等
public ServletConfig getServletConfig();
//取得的是web.xml文件中,<servlet><init-param>配置的參數
public void service(ServletRequestreq, ServletResponse res) throws ServletException,
IOException;
//當servlet的一個客戶端請求到達後,servlet容器就調用相應servlet的service()方法。參數類型分別爲ServletRequest和ServletResponse。前者包含http請求的信息,後者封裝servlet的響應信息。
public String getServletInfo();
//用Servlet類的getServletInfo方法獲取網頁的說明信息,GetServletInfo()方法是一個可選的方法,它提供有關servlet的信息,如作者、版本、版權。
public void destroy();
//在將servlet實例從服務中移出前,servlet容器會調用servlet實例的destory()方法。調用該方法,一般用來清理自身持有的資源,如內存、文件句柄和線程等等。
如何實現一個簡單的servlet容器?
作者給出了一個實例。思路如下:
1:等待HTTP請求。
2:構造一個ServletRequest對象和一個ServletResponse對象。
3:假如該請求需要一個靜態資源的話,調用StaticResourceProcessor實例的process方法,同時傳遞ServletRequest和ServletResponse對象。
4:假如該請求需要一個servlet的話,加載servlet類並調用servlet的service方法,同時傳遞ServletRequest和ServletResponse對象
5: 處理後結果,把封裝爲ServletResponse,返回。
第三章—連接器
tomcat使用的servlet容器的名字是catalina,主要包含2個模塊:連接器(connector)和容器(container)。
連接器
連接器作用:解析http請求頭(其實不只是可以接受http協議,還可以接受AJP協議,用於純web服務器比如apache和應用服務器比如tomcat的連接。關於web服務器和應用服務器的區別,可以自行谷歌之),使得servlet實例能夠獲取到請求頭、cookie等信息。
一個簡單的連接器實現
一個簡單的連接器由2個部分組成:httpConnector、httpProcessor。
httpConnector作用:
1. 等待http請求
2. 爲每個請求創建一個httpProcessor實例
3. 調用httpProcessor的process()方法
核心的代碼如下:
while (!stopped) {
// Acceptthe next incoming connection from the server socket
Socket socket = null;
try {
socket = serverSocket.accept();
}
catch (Exception e) {
continue;
}
// Handthis socket off to an HttpProcessor
HttpProcessor processor = new HttpProcessor(this);
processor.process(socket);
}
httpProcessor作用:創建請求對象和響應對象。顯然,爲了servlet能夠處理,請求對象必須實現httpRequest接口,響應對象必須實現httpResponse接口。
對於每一個傳入的http請求,完成4個操作:
1. 創建一個HttpRequest對象;
2. 創建一個HttpResponse對象;
3. 解析Http的請求行和請求頭,填充HttpRequest對象;
4. 將HttpRequest和HttpResponse傳遞給servlet的service()方法。
解析http請求步驟如下:
1. 讀取套接字的輸入流;
2. 解析請求行;
3. 解析請求頭;
4. 解析cookie;
5. 獲取參數
讀取套接字的輸入流僅需要調用servlet的getInputStream();解析請求行、請求頭、cookie
的parse方法都是按照http協議,比如如何從
“GET /my/app/servlet?username=mohe&password=123 HTTP /1.1”字符串中得到請求方法、URI、版本version。這些都是純字符串操作,大量運用了indexof()、subString()等方法。