1. 程式人生 > >Java實現簡易Tomcat伺服器(清晰易懂)

Java實現簡易Tomcat伺服器(清晰易懂)

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();
        }
    }
}

相關推薦

no