亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Tomcat原理 分類: 原理 2015-06-28 19:26 5人

系統 1814 0

Tomcat的模塊結構設計的相當好,而且其Web 容器的性能相當出色。JBoss直接就使用了Tomcat的web容器,WebLogic的早期版本也是使用了Tomcat的代碼。
Web容器的工作過程在下面的第二個參考文檔中的文檔已經說得相當清楚,我也就不再重復說了。如果不清楚調用過程,需要先看這個文檔。這里分析一下Connector的處理過程。
1. 一個簡單的Web Server示例
這個例子也是從網上找得,不知道原作者,也就不在參考資料中引用了。
這個啟動服務的主程序。
public class HttpServer {
?public static void main(String args[]) {
??int port;
??ServerSocket server_socket; // 讀取服務器端口號
??try {
???port = Integer.parseInt(args[0]);
??} catch (Exception e) {
???port = 8080;
??}
??try {
???// 監聽服務器端口,等待連接請求
???server_socket = new ServerSocket(port);
???System.out.println(”httpServer running on port “
?????+ server_socket.getLocalPort());
???// 顯示啟動信息
???while (true) {
????Socket socket = server_socket.accept();
????System.out.println(”New connection accepted “
??????+ socket.getInetAddress() + “:” + socket.getPort());
????// 創建分線程
????try {
?????HttpRequestHandler request = new HttpRequestHandler(socket);
?????Thread thread = new Thread(request);
?????// 啟動線程
?????thread.start();
????} catch (Exception e) {
?????System.out.println(e);
????}
???}
??} catch (IOException e) {
???System.out.println(e);
??}
?}
}?

?

下面是創建輸出的線程
public class HttpRequestHandler implements Runnable {
?final static String CRLF = “/r/n”;
?Socket socket;
?InputStream input;
?OutputStream output;
?BufferedReader br;
?// 構造方法
?public HttpRequestHandler(Socket socket) throws Exception {
??this.socket = socket;
??this.input = socket.getInputStream();
??this.output = socket.getOutputStream();
??this.br = new BufferedReader(new InputStreamReader(socket
????.getInputStream()));
?}

?

?// 實現Runnable 接口的run()方法
?public void run() {
??try {
???processRequest();
??} catch (Exception e) {
???System.out.println(e);
??}
?}

?

?private void processRequest() throws Exception {
??while (true) {
???// 讀取并顯示Web 瀏覽器提交的請求信息
???String headerLine = br.readLine();
???System.out.println(”The client request is ” + headerLine);
???if (headerLine.equals(CRLF) || headerLine.equals(”"))
????break;
???StringTokenizer s = new StringTokenizer(headerLine);
???String temp = s.nextToken();
???if (temp.equals(”GET”)) {
????String fileName = s.nextToken();
????fileName = “.” + fileName;
????// 打開所請求的文件
????FileInputStream fis = null;
????boolean fileExists = true;
????try {
?????fis = new FileInputStream(”D:/workspace/tomcat/bin/”+fileName);
????} catch (FileNotFoundException e) {
?????fileExists = false;
????}
????// 完成回應消息
????String serverLine = “Server: a simple java httpServer”;
????String statusLine = null;
????String contentTypeLine = null;
????String entityBody = null;
????String contentLengthLine = “error”;
????if (fileExists) {
?????statusLine = “HTTP/1.0 200 OK” + CRLF;
?????contentTypeLine = “Content-type: ” + contentType(fileName) + CRLF;
?????contentLengthLine = “Content-Length: “
???????+ (new Integer(fis.available())).toString() + CRLF;
????} else {
?????statusLine = “HTTP/1.0 404 Not Found” + CRLF;
?????contentTypeLine = “text/html”;
?????entityBody = “<HTML>”
???????+ “<HEAD><TITLE>404 Not Found</TITLE></HEAD>” + “<BODY>404 Not Found” + “<br>usage:http://yourHostName:port/” + “fileName.html</BODY></HTML>”;
????}
????// 發送到服務器信息
????output.write(statusLine.getBytes());
????output.write(serverLine.getBytes());
????output.write(contentTypeLine.getBytes());
????output.write(contentLengthLine.getBytes());
????output.write(CRLF.getBytes());
????// 發送信息內容
????if (fileExists) {
?????sendBytes(fis, output);
?????fis.close();
????} else {
?????output.write(entityBody.getBytes());
????}
???}
??}
??// 關閉套接字和流
??try {
???output.close();
???br.close();
???socket.close();
??} catch (Exception e) {
??}
?}

?

?private static void sendBytes(FileInputStream fis, OutputStream os)
???throws Exception {
??// 創建一個 1K buffer
??byte[] buffer = new byte[1024];
??int bytes = 0;
??// 將文件輸出到套接字輸出流中
??while ((bytes = fis.read(buffer)) != -1) {
???os.write(buffer, 0, bytes);
??}
?}

?

?private static String contentType(String fileName) {
??if (fileName.endsWith(”.htm”) || fileName.endsWith(”.html”)) {
???return “text/html”;
??}
??return “fileName”;
?}
}?
這個簡單的例子說明的web服務的基本實現。Tomcat在此之上模塊化出線程池,網絡連接和WebHttp協議3個包。線程池可獨立使用,網絡連接使用池化,WebHttp直接從網絡連接池中獲取即可。
2. 線程池的實現
這個功能的實現在包 org.apache.tomcat.util.thread 中。
ThreadPool是線程池,是這個功能實現的核心。它使用了所有的其他類進行工作。在類圖中,所有的其他類都是被此類的使用關系。
我們來看此類是如何工作得。
啟動連接池的方法:
?public synchronized void start() {
??stopThePool = false;
??currentThreadCount = 0;
??currentThreadsBusy = 0;

?

??adjustLimits();
??pool = new ControlRunnable[maxThreads];
??openThreads(minSpareThreads);
??if (maxSpareThreads < maxThreads) {
???monitor = new MonitorRunnable(this);
??}
?}?
方法中,根據配置情況,初始化所有線程進入備用狀態。
首先定義maxThreads數目的數組,但是僅僅初始化其中minSpareThreads個。MonitorRunnable用于檢查,是否空閑數目超過 maxSpareThreads個。
currentThreadCount 是當前初始化可以使用的線程數目,而currentThreadsBusy 是當前正在使用的線程數目。
使用連接池的方法:
?public void runIt(ThreadPoolRunnable r) {
??if (null == r) {
???throw new NullPointerException();
??}
??ControlRunnable c = findControlRunnable();
??c.runIt(r);
?}?
該方法中,先尋找可用的線程,找到后在其中運行即可。
找可用線程的方法也很簡單,就是將線程數組中第 currentThreadCount - currentThreadsBusy - 1 個元素取出返回,然后將此元素設成null。
線程運行完畢后,設置currentThreadsBusy– ,然后將 currentThreadCount - currentThreadsBusy - 1 的線程放回就可以了。
線程不夠用就等待,等待失敗就拋出異常。
說明一下上面未提到的類的功能:
ThreadPoolRunnable 這是一個接口,規定了一個線程運行時需要運行的一些動作。這里需要寫一些業務邏輯的代碼了。
ThreadWithAttributes 這個類從上面的代碼中沒有看到,這個類標識當前運行線程的一些特征,比如記錄當前運行線程的一些狀態。
ThreadPoolListener 用于監控ThreadPool中新增線程的情況。
ControlRunnable 這個類是ThreadPool的內部類,用于運行ThreadPoolRunnable 。當ThreadPoolRunnable 運行完畢后,通知ThreadPool回收線程。它時刻處于備用狀態。此對象實例化后,就一直在死循環檢查是否有它需要運行的東西。
3. 網絡連接功能的實現
這個功能的實現在包 org.apache.tomcat.util.net 中。
網絡連接功能構建于線程池之上,實現了一個連接服務模型。服務器打開端口,池化進入連接,為進入的連接創建工作線程。
Tomcat的網絡連接兩個主要的應用是1. 自己提供的web應用。2. 給Apache提供的web應用。這兩個過程的解析過程都是一樣的。僅僅在于網絡連接協議有差別而已。兩個應用都使用此包的功能實現。

?

PoolTcpEndpoint是核心,它使用了ThreadPool。TcpWorkerThread通過調用接口TcpConnectionHandler來完成一次連接需要完成的工作。TcpConnection標識了一個連接對象。
PoolTcpEndpoint的初始化方法代碼很簡單,在構建器中創建或引用ThreadPool,在初始化時創建ServerSocket,用于偵聽客戶端連接。
下面是初始化方法
?public void initEndpoint() throws IOException, InstantiationException {
??try {
???if (factory == null)
????factory = ServerSocketFactory.getDefault();
???if (serverSocket == null) {
????try {
?????if (inet == null) {
??????serverSocket = factory.createSocket(port, backlog);
?????} else {
??????serverSocket = factory
????????.createSocket(port, backlog, inet);
?????}
????} catch (BindException be) {
?????throw new BindException(be.getMessage() + “:” + port);
????}
???}
???if (serverTimeout >= 0)
????serverSocket.setSoTimeout(serverTimeout);
??} catch (IOException ex) {
???// log(”couldn’t start endpoint”, ex, Logger.DEBUG);
???throw ex;
??} catch (InstantiationException ex1) {
???// log(”couldn’t start endpoint”, ex1, Logger.DEBUG);
???throw ex1;
??}
??initialized = true;
?}
?
啟動的方法同樣簡單,僅僅將TcpWorkerThread作為線程池的工作線程,啟動連接池,就大功告成了。
?public void startEndpoint() throws IOException, InstantiationException {
??if (!initialized) {
???initEndpoint();
??}
??if (isPool) {
???tp.start();
??}
??running = true;
??paused = false;
??if (isPool) {
???listener = new TcpWorkerThread(this);
???tp.runIt(listener);
??} else {
???log.error(”XXX Error - need pool !”);
??}
?}
?
偵聽的細節包裝在TcpWorkerThread類中。運行時,它在ServerSocket端口偵聽。當發現有連接進入后,立刻開啟一個新線程繼續偵聽,本線程開始處理連接。下面是代碼:
?public void runIt(Object perThrData[]) {
??// Create per-thread cache
??if (endpoint.isRunning()) {
???// Loop if endpoint is paused
???while (endpoint.isPaused()) {
????try {
?????Thread.sleep(1000);
????} catch (InterruptedException e) {
?????// Ignore
????}
???}
???// Accept a new connection
???Socket s = null;
???try {
????s = endpoint.acceptSocket();
???} finally {
????// Continue accepting on another thread…
????if (endpoint.isRunning()) {
?????endpoint.tp.runIt(this);
????}
???}
???// Process the connection
???if (null != s) {
????TcpConnection con = null;
????int step = 1;
????try {
?????// 1: Set socket options: timeout, linger, etc
?????endpoint.setSocketOptions(s);
?????// 2: SSL handshake
?????step = 2;
?????if (endpoint.getServerSocketFactory() != null) {
?endpoint.getServerSocketFactory().handshake(s);
?????}
?????// 3: Process the connection
?????step = 3;
?????con = (TcpConnection) perThrData[0];
?????con.setEndpoint(endpoint);
?????con.setSocket(s);
?endpoint.getConnectionHandler().processConnection(con,
???????(Object[]) perThrData[1]);
????} catch (SocketException se) {
……?
4. 協議 web http的實現
這個功能的實現在包 org.apache.coyote.http11 中。
對于Http協議的實現核心類是Http11Protocol。具體功能的實現類有MXPoolListener(實現ThreadPoolListener),Http11ConnectionHander(實現TcpConnectionHandler)。
Http11Protocol的初始化方法比較簡單,就是設置一下讓網絡連接開始運行。
Http11ConnectionHander則初始化類Http11Processor,由它解析請求的字符串,交給生成此Connection的Connector的Container,也就是Engine完成。Engine通過遞歸,解析應返回用戶的數據。這個過程在參考文檔中有介紹了。

Tomcat原理 分類: 原理 2015-06-28 19:26 5人閱讀 評論(0) 收藏


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产成人精品aaaa视频一区 | 国产成人综合精品 | 九九热这里只有 | 亚洲一片| 国产羞羞视频在线播放 | 天天做天天爱夜夜爽女人爽宅 | 久久精品国产99精品最新 | 九九碰| 色天天色综合 | 欧美日韩在大午夜爽爽影院 | 日本免费一区二区久久人人澡 | 99国产热 | 牛牛影视免费观看成人 | 久草在线2| 手机看片国产 | 亚洲欧美强伦一区二区另类 | 91视频福利 | 久久伊人最新 | 二级毛片免费观看全程 | 国产精品综合一区二区 | 黄片毛片一级 | 最近中文字幕免费版在线3 最近中文字幕无吗高清视频 | 色鬼综合 | 99热国产这里只有精品 | 免费观看欧美精品成人毛片 | 色吧综合| 91亚洲精品福利在线播放 | 欧美一区二区在线观看视频 | 99精品网站| 久久国产网站 | 性生活视频免费观看 | 亚洲欧美日韩综合二区三区 | 欧美一级片免费 | 国产真实伦视频在线观看 | 国产高清视频在线播放 | aaa国产一级毛片 | 日本一本一区二区 | 久草在线视频免费播放 | 久久制服诱惑 | 经典三级久久久久 | 欧美亚洲综合在线观看 |