Java處理http協議相關初步(二)——httpserver
阿新 • • 發佈:2019-01-28
這裡的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看看
通過下面使用一個簡單的例子,就可以看到怎麼使用它們了,詳細的功能可以檢視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(),設定不同路徑採用不同或相同的處理方法。為什麼繞了這麼多,採用了什麼設計模式,我是還沒到那個高度,期待有人能給留言解說下;或者自己以後慢慢的體會吧!
後面再把這些東西合起來,想個大概的應用場景。
參考