tomcat學習之HTTP應用

1 概述

tomcat啓動的最後時刻,會啓用一個ServerSocket,來接收全部的Web請求(其中大多數是瀏覽器的請求),處理請求後輸出響應到客戶端,好比瀏覽器。 java

Tomcat支持http應用層協議,瀏覽器向tomcat請求資源大多數用的也是http協議。 瀏覽器

本文的重點是,經過簡單的類來模擬tomcat服務,其中特別須要注意的是示例代碼的開發須要遵循HTTP協議。 tomcat

2 代碼展現

2.1 TestSocket服務類

TestSocket類用來模擬tomcat服務,運行他的main方法,能夠啓動服務。TestSocket的關鍵方法和屬性說明以下: 服務器

名稱 異步

類型 socket

說明 ide

serverSocket this

屬性 spa

用於監聽全部的socket鏈接,這裏用於監聽來自瀏覽器的socket鏈接。 .net

poolExecuter

屬性

提供接受者,接受者這裏用於接收socket後,返回響應報文。這種設計思路可以讓tomcat服務器不阻塞的接收socket請求

requestCount

屬性

用於統計請求的次數。

initPoolExecuter

方法

初始化線程池

startServer

方法

啓動服務

     

完整的代碼以下:

package socket;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import thread.Acceptor;

public class TestSocket {

	public TestSocket(){
		initPoolExecuter();
		startServer();
	}
	
	private ServerSocket serverSocket;
	
	private ThreadPoolExecutor poolExecuter;
	
	private int requestCount = 0;
	
	public void initPoolExecuter(){
		LinkedBlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
		poolExecuter = new ThreadPoolExecutor(2, 2, 60, TimeUnit.MINUTES, workQueue);
	}
	
	public void startServer(){
		try {
			System.out.println("tomcat服務已經啓動");
			serverSocket = new ServerSocket(8080, 2);
			while(true){
				Socket socket = serverSocket.accept();
				
				handlerSocket(socket);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 處理請求
	 * @param socket
	 * @throws IOException
	 */
	public void handlerSocket(Socket socket) throws IOException{
		requestCount++;
		System.err.println("第"+requestCount+"次來自客戶端的請求");
		poolExecuter.submit(new Acceptor(socket));
	}
	
	public static void main(String[] args) {
		new TestSocket();
	}
}

2.2 Acceptor接收類

Acceptor是Runnable的實現類,即線程,在TestSocket中經過poolExecuter提供出來,這種設計的思路能夠實現tomcat接收請求和處理請求的異步。

Acceptor類須要作的事情,從socket的InputStream中讀取數據,作完數據處理後,經過socket的OutputStream輸出響應結果。本例子中也只是簡單的輸出了InputStream中全部的數據信息,而後定義了一個響應報文返回給瀏覽器。

關鍵須要闡述的兩點,tomcat的socket請求來源於瀏覽器,tomcat中inputStream中拿到的是瀏覽器發起請求時的請求報文,該報文遵循HTTP協議規範;在tomcat處理完請求,輸出響應數據的時候,tomcat也應該按照HTTP協議的規範,生成響應報文,輸出到瀏覽器,這樣瀏覽器才能正確的解析tomcat返回的處理結果。

完整的代碼以下:

package thread;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Acceptor implements Runnable {

	private Socket socket;
	
	public Acceptor(Socket socket){
		this.socket = socket;
	}
	
	@Override
	public void run() {
		OutputStream outStream = null;
		try{
			InputStream inStream = socket.getInputStream();
			
			byte[] read = new byte[inStream.available()];
			inStream.read(read);
			
			System.err.println("打印請求報文:");
			System.out.write(read);
			
			String response = "HTTP/1.1 200 OK\n"
					+ "Content-type:text/plain\n"
					+ "Content-length:12\n"
					+"\n"
					+ "hello world!";
			
			System.err.println("打印返回報文:");
			System.out.println(response);
			outStream = socket.getOutputStream();
			
			outStream.write(response.getBytes());
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				outStream.flush();
				outStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	}

}

3 待想通的問題

瞭解HTTP協議,以及瀏覽器遵循HTTP協議向tomcat發起socket請求後,模擬tomcat的服務及請求過程就是件比較簡單的事情。若是tomcat在處理完請求後,不按照HTTP協議的規範生成響應報文,這樣不一樣瀏覽器對tomcat的輸出的渲染是不同的,總的來講,都是會存在問題的。

關於瀏覽器訪問tomcat服務的時候,不一樣瀏覽器請求ServerSocket的次數是不同的,其中的緣由,我想多是各種型瀏覽器的實現不太同樣。具體的現象是使用360極速瀏覽器訪問tomcat服務,一次請求過程,能夠監控到最多3次socket鏈接,有時候是兩次;可是使用IE8訪問tomcat服務,一次請求過程,只有一次socket鏈接。雖然發起請求時,不通瀏覽器發起socket的次數不同,可是隻要遵循HTTP協議輸出響應報文,最終的效果都是同樣的,在瀏覽器上只顯示響應報文的實體部份內容。

第二個問題是關於thread代碼執行順序的問題。個人代碼以下:

System.err.println("打印請求報文:");

System.out.write(read);

System.err.println("打印返回報文:");

System.out.println(response);

上述代碼的輸出結果常常是:

這樣代碼和輸出是對應不上的,這地方我猜想是Thread的問題。

最後歡迎你們一塊兒探討這其中存在的問題。

相關文章
相關標籤/搜索