在網路程式設計的學習歷程中,親手打造一個 HTTP 伺服器是理解網路協議與多線程處理的最佳切入點。本文將帶領你逐步實作一個基於 Java Socket 的多線程 HTTP 伺服器,並針對核心邏輯進行深度解析。雖然這是一個教學級別的簡易實作,但它涵蓋了伺服器端處理高併發請求的核心架構:ServerSocket 監聽、accept() 阻塞等待連線、為每個連線獨立啟動執行緒處理業務邏輯。
伺服器主類別 HttpServer 負責初始化通訊埠(預設 8888)並進入無限迴圈監聽客戶端連線。每當有新連線建立,主執行緒便將 Socket 物件交給內部類別 ProcessThread 處理,隨即返回繼續監聽下一個連線。這種「一連線一執行緒」的模型雖然簡單直觀,但在高併發場景下會因頻繁建立/銷毀執行緒而造成效能瓶頸,後續可優化為執行緒池模式。
ProcessThread 繼承 Thread,其 run() 方法完整呈現了 HTTP 請求-回應週期:
BufferedReader 逐行讀取輸入流,直到遇到空行(HTTP 協議規定請求頭以雙 CRLF 結束)。PrintWriter 輸出標準 HTTP 回應,包含狀態行(HTTP/1.0 200 OK)、Content-Type 標頭、空行分隔符,最後輸出 HTML 內容體。finally 區塊確保關閉 Socket,避免檔案描述符洩漏。package thread;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Threaded Network Server
* 簡易多線程 HTTP 伺服器示範
* 採用多線程處理高併發用戶請求
*/
public class HttpServer {
public static void main(String[] args) {
HttpServer hs = new HttpServer();
int i = 1, port = 8888;
Socket received = null;
try {
ServerSocket server = new ServerSocket(port);
System.out.println("伺服器已啟動,監聽埠口:" + port);
while (true) {
received = server.accept();
if (received != null) {
hs.new ProcessThread(i++, received).start();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
class ProcessThread extends Thread {
private int threadNumber = 0;
private Socket received = null;
public ProcessThread(int threadNumber, Socket received) {
super();
this.threadNumber = threadNumber;
this.received = received;
}
@Override
public void run() {
System.out.println("第 " + threadNumber + " 個處理執行緒啟動了……");
if (received != null) {
try {
System.out.println("連接用戶的地址:" + received.getInetAddress().getHostAddress());
InputStream in = received.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = reader.readLine();
while (line != null && !line.equals("")) {
System.out.println(line);
line = reader.readLine();
}
OutputStream out = received.getOutputStream();
PrintWriter writer = new PrintWriter(out, true);
String html = "<html><head><title></title></head><body><h1>收到!</h1></body></html>";
writer.println("HTTP/1.0 200 OK");
writer.println("Content-Type:text/html;charset=GBK");
writer.println(); // 空行結束 Header
writer.println(html);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
received.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
編譯並執行 HttpServer 後,瀏覽器訪問 https://localhost:8888/ 即可看到「收到!」的回應頁面。控制台將輸出執行緒啟動資訊、客戶端 IP 及完整的 HTTP 請求頭,方便觀察協議細節。
作者在原文中規劃了四大演進方向,也是從教學版邁向生產級的關鍵步驟:
Content-Length 並讀取請求體。InputStream/OutputStream 而非 Reader/Writer。ExecutorService 替代顯式 new Thread(),控制併發數量並複用執行緒。Selector + SocketChannel 實現單執行緒多路複用,大幅提升併發上限。這個簡易伺服器雖然功能極簡,卻完整展示了 Java 網路程式設計的基石:Socket 通訊、多線程併發、HTTP 協議解析與回應構建。理解這些基礎機制,才能在後續學習 Netty、Tomcat 等成熟框架時,看透其底層運作原理,做出更合理的架構選型與效能調優。