import java基础.Test718.DefaultThreadPool;
import java基础.Test718.ThreadPool;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleHttpServer {
//处理HttpRequest的线程池
static ThreadPool<HttpRequestHandler> threadPool = new DefaultThreadPool<>();
//SimpleHttpServer
static String basePath;
static ServerSocket serverSocket;
//服务监听端口
static int port = 8080;
// 设置服务端口
public static void setPort(int port){
if(port>0){
SimpleHttpServer.port = port;
}
}
// 设置服务器根路径
public static void setBasePath(String basePath){
if(basePath!=null && new File(basePath).exists() && new File(basePath).isDirectory()){
SimpleHttpServer.basePath = basePath;
}
}
// 启动HTTP服务器
public static void start() throws IOException {
serverSocket = new ServerSocket(port);
Socket socket = null;
while ((socket = serverSocket.accept())!=null){
// 接收一个客户端Socket,生成一个HttpRequestHandler,放入线程池执行
threadPool.execute(new HttpRequestHandler(socket));
}
serverSocket.close();
}
// 处理HTTP请求的线程类
static class HttpRequestHandler implements Runnable {
private Socket socket;
public HttpRequestHandler(Socket socket){
this.socket = socket;
}
@Override
public void run() {
String line = null;
BufferedReader br = null;
BufferedReader reader = null;
PrintWriter out = null;
InputStream in = null;
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String header = reader.readLine();
// 由相对路径计算出绝对路径
String filePath = basePath + header.split(" ")[1];
out = new PrintWriter(socket.getOutputStream());
// 如果请求资源的后缀为jpg或者ico,则先读取资源并输出
if (filePath.endsWith("jpg") || filePath.endsWith("ico")) {
in = new FileInputStream(filePath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = 0;
while ((i = in.read()) != -1) {
baos.write(i);
}
byte[] array = baos.toByteArray();
out.println("HTTP/1.1 200 OK");
out.println("Server: Molly");
out.println("Content-Type: image/jpeg");
out.println("Content-Length: " + array.length);
out.println("");
socket.getOutputStream().write(array, 0, array.length);
} else {
br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
out.println("HTTP/1.1 200 OK");
out.println("Server: Molly");
out.println("Content-Type: text/html; charset=UTF-8");
out.println("");
while ((line = br.readLine()) != null) {
out.println(line);
}
}
out.flush();
} catch (Exception e) {
// 出现异常时返回500错误
out.println("HTTP/1.1 500");
out.println("");
out.flush();
} finally {
// 关闭流或者Socket
close(br, in, reader, out, socket);
}
}
}
// 关闭流或者Socket
private static void close(Closeable... closeables){
if(closeables != null){
for (Closeable closeable : closeables){
try {
closeable.close();
} catch (Exception e) {
// 异常处理
}
}
}
}
}
注释和思路解释:
-
导入相关包:导入所需的Java核心和网络编程相关的类库。
-
定义类和静态成员变量:
SimpleHttpServer
类包含了静态线程池threadPool
,用于处理HTTP请求。basePath
用于存储服务器的根路径。serverSocket
用于监听客户端连接的服务端Socket。port
定义了服务监听的端口,默认为8080。
-
设置端口和基本路径:
setPort(int port)
方法用于设置服务端口。setBasePath(String basePath)
方法用于设置服务器的根路径。
-
启动服务器:
start()
方法通过创建一个ServerSocket监听指定端口,并在接收到客户端连接时,将连接交由HttpRequestHandler
处理,并放入线程池执行。
-
HttpRequestHandler类:
- 内部类,实现了
Runnable
接口,用于处理单个HTTP请求。 - 构造函数接收一个Socket对象,表示与客户端的连接。
- 内部类,实现了
-
run方法:
- 在
run()
方法中,处理HTTP请求的具体逻辑。 - 使用
BufferedReader
从Socket获取输入流,读取HTTP请求的头部信息。 - 根据请求的URL路径(通过HTTP头部获取),拼接出请求的文件路径
filePath
。
- 在
-
处理不同类型的资源:
- 如果请求的资源是jpg或ico类型的,读取对应的文件并返回给客户端。
- 其他类型(默认为HTML文本),读取文件内容并返回。
-
异常处理:
- 如果出现异常,在响应中返回500状态码。
-
关闭资源:
close()
方法用于关闭所有的流和Socket,确保资源正确释放。