日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《How Tomcat Works》读书笔记(三)Connector

發布時間:2025/3/19 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《How Tomcat Works》读书笔记(三)Connector 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么80%的碼農都做不了架構師?>>> ??

3.1 StringManager

為啥要先講StringManager呢?
話說tomcat算是一個大型項目了(最新的tomcat7大概有35W行代碼),因此處理報錯信息就要狠小心,因為報錯信息為開發者和系統管理員提供有用的線索。
tomcat把錯誤信息保存在properties文件中,項目又太大,不能只用一個文件,tomcat為每個需要錯誤信息的package都提供了一個properties文件。
每一個properties文件都是有一個StringManager的實例負責處理。于是tomcat啟動后會存在很多StringManager實例。
每個package中的類共享一個StringManager實例。

public class StringManager {//private構造器,單例private StringManager(String packageName) {...}//包名---StringManager實例映射private static Hashtable<String, StringManager> managers =new Hashtable<String, StringManager>();//考慮了多線程安全,根據包名返回一個StringManager實例 ????public static final synchronized StringManager getManager(String packageName) {StringManager mgr = managers.get(packageName);if (mgr == null) {mgr = new StringManager(packageName);managers.put(packageName, mgr);}return mgr;}//根據errorCode拿到errorMessage//e.g. httpConnector.alreadyInitialized=HTTP connector has already been initializedpublic String getString(String key) {...} } 3.2 ?模塊化

分為三個模塊:connector , startup , core .
startup 模塊只有一個類Bootstrap, 負責啟動應用
connector 模塊包含HttpConnector,HttpProcessor,HttpRequest和HttpResponse
core 模塊包含ServletProcessor和StaticResourceProcessor

我們把《How Tomcat Works》讀書筆記(二)中的HttpServer拆分成兩個類:HttpConnector和HttpProcessor,把Request改成HttpRequest,Response改成HttpResponse。

  • HttpConnector:等待http請求、構建HttpProcessor,并把請求的socket轉交給HttpProcessor
  • HttpProcessor:生成request、response對象,傳遞給ServletProcessor或StaticResourceProcessor
  • HttpRequest ?:implements javax.servlet.http.HttpServletRequest
  • HttpResponse:implements javax.servlet.http.HttpServletResponse
Bootstrap
public final class Bootstrap {public static void main(String[] args) {HttpConnector connector = new HttpConnector();//啟動連接器connector.start();} }

HttpConnector

import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; /** *http連接器 **/ public class HttpConnector implements Runnable {//停止flagboolean stopped;private String scheme = "http";public String getScheme(){return scheme;}public void run(){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 (!stopped) {// 等待下一個到達ServerSocket的連接Socket socket = null;try {socket = serverSocket.accept();}catch (Exception e){continue;}// 把socket轉交給HttpProcessorHttpProcessor processor = new HttpProcessor(this);processor.process(socket);}}public void start(){Thread thread = new Thread(this);thread.start ();} } 我們再來看一下HTTP請求的第一行:
GET /myApp/ModernServlet? userName=tarzan&password=pw d HTTP/1.1?
綠色部分叫做query string

我們再來看一個HTTP請求對應的類:
這一行對應的類就是RequestLine
它下面的請求頭對應的類就是HttpHeader

HttpProcessor
public class HttpProcessor{HttpRequest request;HttpResponse response;private HttpRequestLine requestLine = new HttpRequestLine();public void process(Socket socket) {SocketInputStream input = null;OutputStream output = null;try {input = new SocketInputStream(socket.getInputStream(), 2048);output = socket.getOutputStream();request = new HttpRequest(input);response = new HttpResponse(output);response.setRequest(request);response.setHeader("Server", "Pyrmont Servlet Container");parseRequest(input, output);parseHeaders(input);if (request.getRequestURI().startsWith("/servlet/")) {ServletProcessor processor = new ServletProcessor();processor.process(request, response);}else {StaticResourceProcessor processor = new StaticResourceProcessor();processor.process(request, response);}socket.close();} catch (Exception e) {e.printStackTrace ();}}//解析RequestLineprivate void parseRequest(SocketInputStream input, OutputStream output){...}//解析Headersprivate void parseHeaders(SocketInputStream input,OutputStream output){...} }

3.2.1 Parsing RequestLine

//從SocketInputStream中讀入requestLine input.readRequestLine(requestLine); //獲取http方法 String method = new String(requestLine.method, 0, requestLine.methodEnd); //獲取協議 String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd); //獲取queryString并從URI中排除 int question = requestLine.indexOf("?"); if (question >= 0) {request.setQueryString(new String(requestLine.uri, question + 1, requestLine.uriEnd - question - 1));uri = new String(requestLine.uri, 0, question); } else {request.setQueryString(null);uri = new String(requestLine.uri, 0, requestLine.uriEnd); } //檢查URI是不是絕對路徑(with the HTTP protocol),如果是把URI轉化成相對路徑 if (!uri.startsWith("/")) {int pos = uri.indexOf("://");// Parsing out protocol and host nameif (pos != -1) {pos = uri.indexOf('/', pos + 3);if (pos == -1) {uri = "";} else {uri = uri.substring(pos);}} } //檢查jsessionid是否存在,如果存在,設置request相關屬性并從URI中排除 String match = "jsessionid="; int semicolon = uri.indexOf(match); if (semicolon >= 0) {String rest = uri.substring(semicolon + match,length());int semicolon2 = rest.indexOf(';');if (semicolon2 >= 0) {request.setRequestedSessionId(rest.substring(0, semicolon2));rest = rest.substring(semicolon2);} else {request.setRequestedSessionId(rest); rest = ""; } request.setRequestedSessionURL(true); uri = uri.substring(0, semicolon) + rest; } else {request.setRequestedSessionId(null);request.setRequestedSessionURL(false); } // 糾正URI的錯誤(如把¥替換成/) String normalizedUri = normalize(uri); // Set the corresponding request properties ((HttpRequest) request).setMethod(method); request.setProtocol(protocol); if (normalizedUri != null) {((HttpRequest) request).setRequestURI(normalizedUri); } else {((HttpRequest) request).setRequestURI(uri); } if (normalizedUri == null) {throw new ServletException("Invalid URI: " + uri + "'"); } 3.2.2?Parsing Headers
//構造一個HttpHeader HttpHeader header = new HttpHeader(); //從SocketInputStream中讀出下一個Header input.readHeader(header); //判斷下一個header是否存在 if (header.nameEnd == 0) {if (header.valueEnd == 0) {return;}else {throw new ServletException(sm.getString("httpProcessor.parseHeaders.colon"));????} } //獲取下一個header的name、value String name = new String(header.name, 0, header.nameEnd); String value = new String(header.value, 0, header.valueEnd); //加入到HttpRequest的HashMap<String,String> headers中 request.addHeader(name, value); 除了普通的header還存在一些需要特殊處理的header,如:
content-length header
cookie header
if (name.equals("cookie")) {... // process cookies here } else if (name.equals("content-length")) {int n = -1;try {n = Integer.parseInt (value);} catch (Exception e) {throw new ServletException(sm.getString("httpProcessor.parseHeaders.contentLength")); } request.setContentLength(n); } else if (name.equals("content-type")) {request.setContentType(value); }

3.2.3?Parsing Cookies
下面看一個cookie header的示例?Cookie: userName=budi; password=pwd;
解析cookie用的是org.apache.catalina.util.RequestUtil這個類:

public static Cookie[] parseCookieHeader(String header){if ((header == null) || (header.length 0 < 1) )return (new Cookie[0]); ArrayList cookies = new ArrayList();while (header.length() > 0) {int semicolon = header.indexOf(';');if (semicolon < 0)semicolon = header.length();if (semicolon == 0)break;String token = header.substring(0, semicolon);if (semicolon < header.length())header = header.substring(semicolon + 1);elseheader = "";try {int equals = token.indexOf('=');if (equals > 0) {String name = token.substring(0, equals).trim();String value = token.substring(equals+1).trim();cookies.add(new Cookie(name, value)); }}catch (Throwable e) {; }}return ((Cookie[]) cookies.toArray (new Cookie [cookies.size ()])); } 在HttpProcessor中我們這樣就使用它來解析cookie:
else if (header.equals(DefaultHeaders.COOKIE_NAME)) {Cookie cookies[] = RequestUtil.ParseCookieHeader (value);for (int i = 0; i < cookies.length; i++) {if (cookies[i].getName().equals("jsessionid")) {// Override anything requested in the URLif (!request.isRequestedSessionIdFromCookie()) {// Accept only the first session id cookierequest.setRequestedSessionId(cookies[i].getValue());request.setRequestedSessionCookie(true);request.setRequestedSessionURL(false);}}request.addCookie(cookies[i]);} } 3.2.4?Obtaining Parameters
請求參數可能存在queryString和Http request body中。我們都要進行檢查。
//解析queryString中的參數 String queryString = getQueryString(); try {RequestUtil.parseParameters(results, queryString, encoding); } catch (UnsupportedEncodingException e) {; } //解析request body中的參數 String contentType = getContentType(); if (contentType == null)contentType = ""; int semicolon = contentType.indexOf(';'); if (semicolon >= 0) {contentType = contentType.substring (0, semicolon).trim(); } else {contentType = contentType.trim(); } if ("POST".equals(getMethod()) && (getContentLength() > 0)&& "application/x-www-form-urlencoded".equals(contentType)) {try {int max = getContentLength();int len = 0;byte buf[] = new byte[getContentLength()];ServletInputStream is = getInputStream();while (len < max) {int next = is.read(buf, len, max - len);if (next < 0 ) {break;}len += next;}is.close();if (len < max) {throw new RuntimeException("Content length mismatch");}RequestUtil.parseParameters(results, buf, encoding);} catch (UnsupportedEncodingException ue) {;} catch (IOException e) {throw new RuntimeException("Content read fail");} }



轉載于:https://my.oschina.net/itjava/blog/102428

總結

以上是生活随笔為你收集整理的《How Tomcat Works》读书笔记(三)Connector的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。