手書きMini版Tomcatサーバ
10485 ワード
手書きMini版Tomcatサーバ
オリジナル:sean 9468プログラマー文章集錦原文アドレス
きほんげんり
Tomcatサーバはservletコンテナで、主にjavaWebプロジェクトの導入に使用されます.Tomcatは主にsocketを傍受し、入力ストリーム、出力ストリームを獲得し、httpパケットを解析してrequest、responseを作成し、servletを呼び出すことを実現した.doFilterとservlet.サービス関数はresponse情報を埋め込み、クライアント出力ストリームに書き込む.
コアコード
詳細コードは原文をクリックしてgiteeアドレスを表示します.
コアコード:
テストコード:サーブレットと静的HTMLファイル.
Bootstrap
起動クラスは1つの主関数であり,Webプロジェクト全体のエントリであり,通常開発用のwarパッケージにはプロジェクトエントリはなく,実際にはTomcatの起動クラスにある.すなわちspring bootを用いた開発もtomcatの依存を含みjarパッケージにパッケージ化されている.同じ理屈だ.
コネクタ
コネクタHttpConnectorの主な目的は、同期ブロックを使用してポートをリスニングすることです.リスニングコードは、新しいスレッドが担当します.すべてのクライアントリクエストは同じスレッドで処理され、効率は最良ではありませんが、小さなトラフィックを安定させるには可能です.スレッドとIOモデルについても重要な技術面である.ここでは多く述べるにすぎない.
Http処理クラス
これはコアクラスで、Tomcatでもコネクタの役割範囲に属し、主にRequestとResponseを生成します.ここで、RequestのHeader Cookie RequestLine RequestParaパラメータは、一つ一つ解析されます.この部分はHTTPプロトコルについてもっと深く理解します.
プロセスメソッド
クライアントのInputStreamをさらにSocketInputStreamにカプセル化し、HttpRequestを作成し、HTTPヘッダ情報を解析し、HttpResponseを作成する.ここでは主にGETリクエストです.解析したURIからサーブレット処理するか静的ファイル処理するかを判断する.サーブレットは、作成したテストサーブレットコードを呼び出し、静的リソースはローカルの静的htmlファイルを処理し、見つからない場合は404に戻ります.
RequestLineの解析
クライアントのInputStreamをさらにSocketInputStreamにカプセル化し、HTTPの最初の行を解析するHTTP method、HTTP URI、HTTP protocol、versionであるカプセル化されたRequestLineを実現する.次にRequestのmethod,URI,protocolに値を割り当てます.注意:RequestLineの解析は、Headerの解析よりも優先されます.
解析Headers
Headers情報は、実はname-valueキー値ペアのみであり、cookies、content-length、user-agentなど、異なるnameに基づいて異なる要素を抽出することができる.抽出ヘッドはループであり、読み取りが完了するまでループごとにヘッドが作成されます.
サーブレット処理クラス
このサーブレット処理クラスは、URI要求の名前に従ってサーブレットClassをロードし、サービス関数をインスタンス化し、呼び出す.サービス参照についてはRequestとResponseのファセットクラスが実際に伝達されている.主な目的は,不要なインタフェースがサーブレットビジネスプログラマーに漏れることを安全に回避することである.
}
HttpResponse
ここでは静的ファイルを処理するコードをHttpResponse,sendStaticResourceメソッドに格納する.
デバッグ運転
PrimitiveServiceのリクエスト
リクエストtest.html要求test-notfound.html
オリジナル:sean 9468プログラマー文章集錦原文アドレス
きほんげんり
Tomcatサーバはservletコンテナで、主にjavaWebプロジェクトの導入に使用されます.Tomcatは主にsocketを傍受し、入力ストリーム、出力ストリームを獲得し、httpパケットを解析してrequest、responseを作成し、servletを呼び出すことを実現した.doFilterとservlet.サービス関数はresponse情報を埋め込み、クライアント出力ストリームに書き込む.
コアコード
詳細コードは原文をクリックしてgiteeアドレスを表示します.
コアコード:
:BootStrap
:HttpConnector
http :HttpProcessor
HttpRequest
HttpResponse
:RequesFacade
:ResponseFacade
テストコード:サーブレットと静的HTMLファイル.
PrimitiveServle
test.html
Bootstrap
起動クラスは1つの主関数であり,Webプロジェクト全体のエントリであり,通常開発用のwarパッケージにはプロジェクトエントリはなく,実際にはTomcatの起動クラスにある.すなわちspring bootを用いた開発もtomcatの依存を含みjarパッケージにパッケージ化されている.同じ理屈だ.
public class BootStrap {
public static void main(String[] args) {
HttpConnector connector = new HttpConnector();
connector.start();
}
}
コネクタ
コネクタHttpConnectorの主な目的は、同期ブロックを使用してポートをリスニングすることです.リスニングコードは、新しいスレッドが担当します.すべてのクライアントリクエストは同じスレッドで処理され、効率は最良ではありませんが、小さなトラフィックを安定させるには可能です.スレッドとIOモデルについても重要な技術面である.ここでは多く述べるにすぎない.
public class HttpConnector implements Runnable {
boolean stopped;
private String scheme = "http";
public String getScheme() {
return scheme;
}
public void start() {
Thread thread = new Thread(this);
thread.start();
}
@Override
public void run() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket = new ServerSocket(port, 100, InetAddress.getByName("127.0.0.1"));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
while (!stopped) {
Socket socket = null;
try {
socket = serverSocket.accept();
} catch (IOException e) {
e.printStackTrace();
continue;
}
HttpProcessor processor = new HttpProcessor();
processor.process(socket);
}
}
}
Http処理クラス
これはコアクラスで、Tomcatでもコネクタの役割範囲に属し、主にRequestとResponseを生成します.ここで、RequestのHeader Cookie RequestLine RequestParaパラメータは、一つ一つ解析されます.この部分はHTTPプロトコルについてもっと深く理解します.
プロセスメソッド
クライアントのInputStreamをさらにSocketInputStreamにカプセル化し、HttpRequestを作成し、HTTPヘッダ情報を解析し、HttpResponseを作成する.ここでは主にGETリクエストです.解析したURIからサーブレット処理するか静的ファイル処理するかを判断する.サーブレットは、作成したテストサーブレットコードを呼び出し、静的リソースはローカルの静的htmlファイルを処理し、見つからない場合は404に戻ります.
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", "sean 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 (IOException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
}
}
RequestLineの解析
クライアントのInputStreamをさらにSocketInputStreamにカプセル化し、HTTPの最初の行を解析するHTTP method、HTTP URI、HTTP protocol、versionであるカプセル化されたRequestLineを実現する.次にRequestのmethod,URI,protocolに値を割り当てます.注意:RequestLineの解析は、Headerの解析よりも優先されます.
input.readRequestLine(requestLine);
String method = new String(requestLine.method, 0, requestLine.methodEnd);
String uri;
String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd);
if (method.length() < 1) {
throw new ServletException("Missing Http request method");
} else if (requestLine.uriEnd < 1) {
throw new ServletException("Missing Http request 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);
}
if (!uri.startsWith("/")) {
int pos = uri.indexOf("://");
if (pos == -1) {
uri = "";
} else {
uri = uri.substring(pos);
}
}
request.setUri(uri);
request.setMethod(method);
request.setProtocol(protocol);
}
解析Headers
Headers情報は、実はname-valueキー値ペアのみであり、cookies、content-length、user-agentなど、異なるnameに基づいて異なる要素を抽出することができる.抽出ヘッドはループであり、読み取りが完了するまでループごとにヘッドが作成されます.
private void parseHeaders(SocketInputStream input) throws IOException, ServletException {
while (true) {
httpHeader = new HttpHeader();
input.readHeader(httpHeader);
if (httpHeader.nameEnd == 0) {
if (httpHeader.valueEnd == 0) {
return;
} else {
throw new ServletException("parseHeaders exceptions");
}
}
request.addHeader(httpHeader);
if (httpHeader.name.equals("cookie")) {
Cookie cookies[] = RequestUtil.parseCookieHeader(new String(httpHeader.value));
for (int i = 0; i < cookies.length; i++) {
request.addCookie(cookies[i]);
}
} else if (httpHeader.name.equals("content-length")) {
int n = Integer.parseInt(new String(httpHeader.value));
request.setContentLength(n);
}
}
}
サーブレット処理クラス
このサーブレット処理クラスは、URI要求の名前に従ってサーブレットClassをロードし、サービス関数をインスタンス化し、呼び出す.サービス参照についてはRequestとResponseのファセットクラスが実際に伝達されている.主な目的は,不要なインタフェースがサーブレットビジネスプログラマーに漏れることを安全に回避することである.
public class ServletProcessor {
public void process(HttpRequest request, HttpResponse response) {
String uri = request.getRequestURI();
String servletName = uri.substring(uri.lastIndexOf("/") + 1);
URLClassLoader loader = null;
try {
URL[] urls = new URL[1];
URLStreamHandler streamHandler = null;
File classPath = new File(Constants.WEB_ROOT);
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
loader = new URLClassLoader(urls);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Class myClass = null;
try {
servletName = "tomcat.step3.servlet." + servletName;
myClass = loader.loadClass(servletName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Servlet servlet = null;
try {
servlet = (Servlet) myClass.newInstance();
RequestFacade requestFacade = new RequestFacade(request);
ResponseFacade responseFacade = new ResponseFacade(response);
servlet.service(requestFacade, responseFacade);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
HttpResponse
ここでは静的ファイルを処理するコードをHttpResponse,sendStaticResourceメソッドに格納する.
public void sendStaticResource() throws IOException {
byte[] bytes = new byte[BUFFER_SIZE];
try {
File file = new File(HttpServer.WEB_ROOT, httpRequest.getRequestURI());
System.out.println(file.getAbsolutePath());
if (file.exists()) {
System.out.println(" ");
InputStreamReader reader = new InputStreamReader(new FileInputStream(file));
BufferedReader reader1 = new BufferedReader(reader);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output));
String line = null;
while ((line = reader1.readLine()) != null) {
System.out.println(line);
writer.write(line);
}
writer.flush();
writer.close();
reader.close();
reader1.close();
} else {
String erroMessage = "HTTP/1.1 404 Fie Not Found\r
" +
"Content-Type: text/html\r
" +
"Content-length:23\r
" +
"\r
" +
"File Not Found";
output.write(erroMessage.getBytes());
}
} catch (Exception e) {
System.out.println(e.toString());
} finally {
}
}
デバッグ運転
PrimitiveServiceのリクエスト
リクエストtest.html要求test-notfound.html