Java實現簡易Tomcat伺服器(清晰易懂)
阿新 • • 發佈:2019-01-16
Tomcat伺服器是一個輕量級的Java程式碼實現的WEB伺服器。這篇文章將會講述如何用Java實現一個簡易版的Tomcat伺服器。
簡單的講,簡易原理是這樣的:
1. Tomcat開始執行之後,會在主機上開一個埠(預設是80埠),在所開闢的埠上執行一個ServerSocket,執行accept()方法等待瀏覽器訪問。
2. 瀏覽器訪問目標主機的80埠,ServerSocket的accept()方法返回一個執行在伺服器端的socket,該socket有getInputStream()方法和getOutputStream方法,可以獲得瀏覽器對伺服器傳送的內容和響應瀏覽器併發送內容。
3. 瀏覽器收到伺服器響應的內容,通過瀏覽器解釋,內容顯示在使用者眼前。
注意:
1. 瀏覽器傳送給伺服器的訪問請求符合HTTP協議。
2. 瀏覽器可以像伺服器請求一個HTML頁面,也可以請求圖片,若HTML頁面中匯入了圖片或者css,js,則這些內容也會像伺服器請求,伺服器會根據檔名,對瀏覽器進行響應,若該檔案在伺服器目錄中找不到,則返回404錯誤。
3. 本簡易Tomcat伺服器只適用於靜態資源。
4. 本簡易Tomcat分為兩個類,Server類以及Handler類,Server類接收請求,然後建立子執行緒,到Handler類中去處理瀏覽器傳送的請求,並反饋。
程式碼及註釋如下:
package com.yykj; import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { Server server = new Server(); server.startServer(); } public void startServer(){ try { ServerSocket serverSocket = new ServerSocket(80);//開啟80埠 System.out.println("伺服器啟動>>> 80埠"); while(true){//開啟一個永遠的迴圈,一直等待客戶訪問80埠 Socket socket = serverSocket.accept(); Thread thread = new Thread(new Handler(socket));//當有客戶訪問時,開闢一個新執行緒處理該請求 System.out.println("收到新請求"); thread.start(); } } catch (IOException e) { e.printStackTrace(); } } }
Handler類:
package com.yykj; import java.io.*; import java.net.Socket; //請求處理程式 public class Handler implements Runnable { private Socket socket; private OutputStream outputStream; private InputStream inputStream; private BufferedReader reader; private PrintWriter writer; private static String WEB_ROOT = "C:\\Users\\Administrator\\Desktop\\web";//伺服器儲存檔案目錄 public Handler(Socket socket){ this.socket = socket; } @Override public void run(){ try{ inputStream = socket.getInputStream();//伺服器到客戶的輸出流 outputStream = socket.getOutputStream();//客戶到伺服器的輸入流 reader = new BufferedReader(new InputStreamReader(inputStream));//包裝後的輸入緩衝字元流 writer = new PrintWriter(new OutputStreamWriter(outputStream));//包裝後的輸出緩衝字元流 String msg;//接收客戶端請求的臨時字串 StringBuffer request = new StringBuffer();//將請求拼接成完整的請求 while((msg = reader.readLine()) != null && msg.length() > 0){ request.append(msg); request.append("\n");//HTTP協議的格式 } String[] msgs = request.toString().split(" ");//HTTP協議以空格為分隔符 //msgs[1]代表了HTTP協議中的第二個字串,是瀏覽器請求的檔名 /* if(msgs[1].endsWith(".ico")){//.ico檔案是瀏覽器頁面的圖示檔案,是瀏覽器預設會向伺服器傳送的請求 writer.println("HTTP/1.1 200 OK");//如果伺服器不打算對客戶端傳送.ico結尾的檔案,可以這一寫,然後直接返回,跳過傳送該檔案的過程 writer.println("Content-Type: text/html;charset=UTF-8"); writer.close(); //如果不傳送,就直接返回 return; }*/ //將伺服器目錄下被請求的檔案讀入程式 FileInputStream fileInputStream = new FileInputStream(new File(WEB_ROOT + msgs[1])); byte[] fileBuffer = new byte[1024];//可能是二進位制檔案,所以需要用byte陣列做緩衝 int length = 0; while((length = fileInputStream.read(fileBuffer)) != -1){ outputStream.write(fileBuffer, 0, length);//向客戶端瀏覽器傳送檔案 } outputStream.close(); inputStream.close(); reader.close(); fileInputStream.close(); }catch (IOException e){ //如果丟擲異常,在這裡基本上是未找到被請求檔案,所以返回404 writer.write("HTTP/1.1 404 ERROR:FILE NOT FINDED"); writer.close(); } } }