面向对象程序设计(Java)课程设计

2026年06月26日


一、项目简介

功能描述: 本项目使用Java Socket网络编程实现了一个简易的多线程HTTP服务器,支持GET、POST和HEAD三种HTTP请求方法,能够根据浏览器指定的URL返回服务器上相应的网页文件,并实现了日志记录和安全防护功能。

有无参考他人代码: 参考了HTTP协议相关资料及Java Socket编程示例,核心代码均为自主编写。

参考git地址或博客地址:

  • http://blog.csdn.net/earbao/article/details/16354881
  • http://zsxxsz.iteye.com/blog/568250
  • http://www.cnblogs.com/zhijianliutang/archive/2012/09/23/2698860.html

二、功能架构图

请添加图片描述

三、个人任务简述

本人主要负责HTTP服务器的核心协议处理模块,包括HTTP请求的解析、HTTP响应的构建、服务器主框架的设计与实现以及日志工具类的开发。

1. 完成的任务与功能:

序号 完成功能与任务 描述
1 HTTP请求解析模块 使用BufferedInputStream实现HttpRequest类,逐字节扫描\r\n\r\n标记,准确解析请求行、请求头和请求体,支持URL解码
2 HTTP响应构建模块 实现HttpResponse类,使用工厂模式提供6种状态码的创建方法,自动添加Server、Date等标准响应头
3 服务器主框架设计 实现HttpServer类,使用ServerSocket监听端口,ExecutorService线程池管理并发连接
4 协议处理逻辑 实现HTTP/1.1协议处理,支持GET、POST、HEAD三种方法,使用switch-case分发请求
5 日志工具类 实现Logger类,支持INFO、ERROR、WARN三种日志级别和访问日志记录

四、本人负责功能详解

1. *HTTP请求解析模块

简述: HTTP请求解析模块负责将客户端发送的原始HTTP请求字节流解析为结构化的请求对象。采用BufferedInputStream逐字节读取,检测\r\n\r\n标记头部结束,避免BufferedReader缓冲区干扰POST数据读取的问题。

难点与解决方法:

  • 难点:BufferedReader内部缓冲区会干扰POST数据读取,导致请求超时
  • 解决:改用BufferedInputStream + ByteArrayOutputStream,逐字节扫描头部结束标记
public static HttpRequest parse(InputStream inputStream) {
    BufferedInputStream bis = new BufferedInputStream(inputStream);
    ByteArrayOutputStream headerBuffer = new ByteArrayOutputStream();
    int prev = 0, curr;
    boolean headerEnd = false;
    while ((curr = bis.read()) != -1) {
        headerBuffer.write(curr);
        if (prev == '\r' && curr == '\n') {
            byte[] buf = headerBuffer.toByteArray();
            int len = buf.length;
            if (len >= 4 && buf[len-4] == '\r' && buf[len-3] == '\n'
                        && buf[len-2] == '\r' && buf[len-1] == '\n') {
                headerEnd = true;
                break;
            }
        }
        prev = curr;
    }
    // 解析请求行和请求头...
}

2. *HTTP响应构建模块

简述: HTTP响应构建模块使用工厂模式,为每种HTTP状态码提供静态创建方法。支持200 OK、400 Bad Request、403 Forbidden、404 Not Found、405 Method Not Allowed、500 Internal Server Error六种状态码。

难点与解决方法:

  • 难点:需要支持多种状态码,每种有不同的响应体
  • 解决:采用工厂模式,每种状态码对应一个静态create方法
public static HttpResponse createOk(String contentType, byte[] body) {
    HttpResponse response = new HttpResponse();
    response.statusCode = 200;
    response.statusMessage = "OK";
    response.headers.put("Content-Type", contentType);
    response.headers.put("Content-Length", String.valueOf(body.length));
    response.body = body;
    return response;
}

public static HttpResponse createNotFound() {
    HttpResponse response = new HttpResponse();
    response.statusCode = 404;
    response.statusMessage = "Not Found";
    String body = "<html><body><h1>404 Not Found</h1></body></html>";
    response.headers.put("Content-Type", "text/html; charset=UTF-8");
    response.body = body.getBytes();
    return response;
}

3. *服务器主框架设计

简述: 服务器主框架是系统的入口和控制中心,使用ServerSocket监听端口,ExecutorService线程池管理并发连接,支持命令行参数指定端口号。

难点与解决方法:

  • 难点:需要支持多个客户端同时连接
  • 解决:使用FixedThreadPool线程池,大小为10,为每个连接提交独立任务
public void start() {
    try {
        serverSocket = new ServerSocket(port);
        running = true;
        Logger.info("简易HTTP服务器启动成功");
        Logger.info("监听端口: " + port);
        while (running) {
            Socket clientSocket = serverSocket.accept();
            threadPool.submit(new ClientHandler(clientSocket));
        }
    } catch (IOException e) {
        Logger.error("服务器异常: " + e.getMessage());
    }
}

4. 日志工具类

简述: 实现Logger日志工具类,支持INFO、ERROR、WARN三种日志级别和访问日志记录,所有日志带时间戳,便于调试和监控。

public class Logger {
    private static final DateTimeFormatter FORMATTER =
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static void info(String message) {
        System.out.println("[" + LocalDateTime.now().format(FORMATTER)
            + "] [INFO] " + message);
    }

    public static void access(String clientIp, String method,
                              String url, int statusCode) {
        System.out.println("[" + LocalDateTime.now().format(FORMATTER)
            + "] " + clientIp + " " + method + " " + url + " " + statusCode);
    }
}

五、课程设计感想

在本次课程设计中,我深入学习了HTTP协议和Java Socket网络编程,遇到了不少困难,也收获了很多经验。

遇到的困难及解决过程:

  1. POST请求超时问题:最初使用BufferedReader读取HTTP请求,发现curl发送的POST请求会超时。经过调试发现是BufferedReader的内部缓冲区在读取请求头时已经消费了部分POST body字节,导致后续读取阻塞。最终改用BufferedInputStream逐字节读取,精确控制字节位置,解决了这个问题。

  2. URL编码问题:浏览器发送的URL可能包含编码字符(如中文),需要正确解码。使用URLDecoder.decode()方法解决了这个问题。

  3. 多线程资源管理:在多线程环境下,需要确保每个线程正确释放资源。通过使用try-finally语句和适当的异常处理,解决了资源泄漏问题。

收获与体会:

通过本次课程设计,我不仅掌握了HTTP服务器的基本原理和实现方法,还提高了面向对象设计能力。深刻体会到了模块化设计的重要性,合理的模块划分使得代码更易于维护和扩展。同时,也认识到了网络编程中细节处理的重要性,一个小小的缓冲区问题就可能导致整个功能失效。


六、展望

1. 自己所完成功能的不足之处及改进方法:

  1. 协议支持有限:目前仅支持GET、POST、HEAD三种方法,未来可增加PUT、DELETE等方法的支持。

  2. 性能优化:当前线程池大小固定为10,未来可根据负载动态调整,或使用NIO技术提高性能。

2. 课设后想要进一步做的事情:

  1. 学习NIO编程:深入学习Java NIO技术,实现更高性能的非阻塞HTTP服务器。

  2. 研究HTTP/2协议:了解HTTP/2协议的新特性,如多路复用、头部压缩等。

  3. 增加动态内容处理:支持Servlet规范,实现动态内容生成。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐