1. 程式人生 > >Java處理http協議相關初步(二)——httpserver

Java處理http協議相關初步(二)——httpserver

    這裡的HttpServer,並不是哪裡專門下載的類庫了,而是在JDK1.6中自帶的,在com.sun.net.httpserver包中,提供了簡單的較高層次意義上的Http ServerAPI,可以構建內建的HTTP Server,支援Http和Https協議,提供了HTTP1.1的部分實現,沒有被實現的那部分可以通過擴充套件已有的Http Server API來實現。程式設計師必須自己實現HttpHandler介面,HttpServer會呼叫HttpHandler實現類的回撥方法來處理客戶端請求,在這裡,我們把一個Http請求和它的響應稱為一個交換,包裝成HttpExchange類,HttpServer負責將HttpExchange傳給HttpHandler實現類的回撥方法. (摘過來的,也是官方的描述說明)
    通過下面使用一個簡單的例子,就可以看到怎麼使用它們了,詳細的功能可以檢視API文件。訪問localhost:8086/ 和 localhost:8086/test看看
package com.test.myjava;

import java.io.IOException;  
import java.io.OutputStream; 
import java.net.InetSocketAddress; 
import java.util.Queue;
import java.util.concurrent.*;

import com.sun.net.httpserver.HttpExchange; 
import com.sun.net.httpserver.HttpHandler; 
import com.sun.net.httpserver.HttpServer; 
public class HttpServerTest { 
	public static void main(String[] args) {
		try {
			//允許最大連線數
			int backLog = 10;
			InetSocketAddress inetSock = new InetSocketAddress(8086);
			HttpServer httpServer = HttpServer.create(inetSock, backLog);
			//直接返回Hello.....
			httpServer.createContext("/", new HandlerTestA());
			//顯示已經處理的請求數,採用執行緒池
			httpServer.createContext("/test",new HandlerTestB());
			httpServer.setExecutor(null);
			httpServer.start();
			System.out.println("HttpServer Test Start!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

//直接處理請求
class HandlerTestA implements HttpHandler{

	public void handle(HttpExchange httpExchange) throws IOException {
		// TODO Auto-generated method stub
		//針對請求的處理部分   
		//返回請求響應時,遵循HTTP協議
		String responseString = "<font color='#ff0000'>Hello! This a HttpServer!</font>";
		//設定響應頭
		httpExchange.sendResponseHeaders(200, responseString.length());   
		OutputStream os = httpExchange.getResponseBody();   
		os.write(responseString.getBytes());   
		os.close(); 
	}
	
}
//執行緒池還不會用,簡略的使用了下,意思有點差距,後面在分析
class HandlerTestB implements HttpHandler{
	private static int requestNum = 0; 
	ThreadPoolExecutor threadPoolExecutor;
	HandlerTestB(){
		//兩個常線上程,最大3個
		 threadPoolExecutor = new  ThreadPoolExecutor(2,3, 30, 
				 TimeUnit.SECONDS, 
				 new ArrayBlockingQueue<Runnable>(2),  
		         new ThreadPoolExecutor.CallerRunsPolicy()
				 );
	}
	public void handle(HttpExchange he) throws IOException {
		// TODO Auto-generated method stub
		if((getQueueSize(threadPoolExecutor.getQueue()))<2){
			RequestTasks rqt = new RequestTasks(he); 
			threadPoolExecutor.execute(rqt);
		}
		else System.out.println("Please Wait!");
	}
	private synchronized int getQueueSize(Queue queue)  
    {  
        return queue.size();  
    } 
	
}

//處理請求的任務
class RequestTasks implements Runnable{

	static int processedNum = 0;
	HttpExchange httpExchange;
	RequestTasks(HttpExchange he){
		httpExchange = he;
		processedNum++;
	}
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("ProcessedNum:" +processedNum);
		String responseString = "ProcessedNum:" + processedNum + "\n";
		try{
		httpExchange.sendResponseHeaders(200, responseString.length());   
		OutputStream os = httpExchange.getResponseBody();   
		os.write(responseString.getBytes());   
		os.close();
		//去掉註釋,看看只能響應兩個,有些問題
		//while(true);
		}catch (Exception e){
			e.printStackTrace();
		}
	}
	
}

    看這些的時候有個小插曲,當時看不懂既然有了createContext ( )方法中的實現HttpHandler介面的類來處理請求,為什麼又要有個setExecutor來設定管理執行緒的Executor,而且還要在start()方法之前;這時自己檢視文件的時候看到createContext(),start()方法都是抽象方法(當然HttpServer也是抽象類),是怎麼呼叫的呢?在網上找到其原始碼時,才發現,HttpServer的建立首先是通過create(InetSocketAddress addr, int backlog)這個靜態方法建立,這裡面是通過 HttpServerProvider(它也是抽象類,其子類 sun.net.httpserver.DefaultHttpServerProvider中的createHttpServer)來建立的,其後在具體建立過程中則是new了一個 HttpServerImpl類的例項(這個只是一個包裝,具體實現是ServerImpl類來完成最後的HttpServer物件的生成);檢視ServerImpl的實現,才知道setExecutor設定的是處理TCP連結請求的執行緒,而createContext 裡設定的是針對具體的請求進行處理的回撥方法,而且可以通過設定呼叫多次createContext(),設定不同路徑採用不同或相同的處理方法。為什麼繞了這麼多,採用了什麼設計模式,我是還沒到那個高度,期待有人能給留言解說下;或者自己以後慢慢的體會吧!

    後面再把這些東西合起來,想個大概的應用場景。

參考