基於 `ServerSocket` + 多執行緒模型:主執行緒監聽端口,每個客戶端連接啟動一條 `ConnectionThread` 處理通信。
// WebServer.java
import java.io.*;
import java.net.*;
public class WebServer {
public static void main(String args[]) {
int i = 1, PORT = 8080;
ServerSocket server = null;
Socket client = null;
try {
server = new ServerSocket(PORT);
System.out.println("Web Server is listening on port " + server.getLocalPort());
for (;;) {
client = server.accept(); // 阻塞等待客戶端連接
new ConnectionThread(client, i).start();
i++;
}
} catch (Exception e) {
System.out.println(e);
}
}
}
/* ConnectionThread:處理單個瀏覽器通信 */
class ConnectionThread extends Thread {
Socket client;
int counter;
public ConnectionThread(Socket cl, int c) {
client = cl;
counter = c;
}
public void run() {
try {
String destIP = client.getInetAddress().toString();
int destPort = client.getPort();
System.out.println("Connection " + counter + ": connected to " + destIP + " on port " + destPort + ".");
PrintStream outStream = new PrintStream(client.getOutputStream());
DataInputStream inStream = new DataInputStream(client.getInputStream());
String inLine = inStream.readLine(); // 讀取 HTTP 請求行
System.out.println("Received: " + inLine);
if (getRequest(inLine)) { // 僅處理 GET 請求
String fileName = getFileName(inLine);
File file = new File(fileName);
if (file.exists()) {
// 返回 200 OK + 文件內容
System.out.println(fileName + " requested.");
outStream.println("HTTP/1.0 200 OK");
outStream.println("MIME_version: 1.0");
outStream.println("Content_Type: text/html");
int len = (int) file.length();
outStream.println("Content_Length: " + len);
outStream.println(""); // 空行分隔 Header 與 Body
sendFile(outStream, file);
outStream.flush();
} else {
// 返回 404 Not Found
String msg = "Not Found Error 404 - file not found
";
outStream.println("HTTP/1.0 404 Not Found");
outStream.println("Content_Type: text/html");
outStream.println("Content_Length: " + (msg.length() + 2));
outStream.println("");
outStream.println(msg);
outStream.flush();
}
}
// 簡單延遲模擬處理時間
long m1 = 1;
while (m1 < 11100000) { m1++; }
client.close();
} catch (IOException e) {
System.out.println("Exception: " + e);
}
}
/* 判斷是否為 GET 請求 */
boolean getRequest(String s) {
if (s.length() > 0 && s.substring(0, 3).equalsIgnoreCase("GET"))
return true;
return false;
}
/* 從請求行解析文件名 */
String getFileName(String s) {
String f = s.substring(s.indexOf(' ') + 1);
f = f.substring(0, f.indexOf(' '));
try {
if (f.charAt(0) == '/') f = f.substring(1);
} catch (StringIndexOutOfBoundsException e) {
System.out.println("Exception: " + e);
}
if (f.equals("")) f = "index.html";
return f;
}
/* 發送文件內容到輸出流 */
void sendFile(PrintStream out, File file) {
try {
DataInputStream in = new DataInputStream(new FileInputStream(file));
int len = (int) file.length();
byte[] buf = new byte[len];
in.readFully(buf);
out.write(buf, 0, len);
out.flush();
in.close();
} catch (Exception e) {
System.out.println("Error retrieving file.");
System.exit(1);
}
}
}
這個極簡 Web Server 能跑通 HTTP 基礎流程,是理解 Servlet 容器(如 Tomcat)底層原理的絕佳切入點。