手写一个简单的tomcat(从零到一,简单易懂)

本文介绍了如何从概念上理解和使用Tomcat进行JavaWeb应用程序的部署、管理,涉及Web服务器工作原理、性能优化、调试技巧以及实现一个简单的自定义Tomcat服务器,包括接收请求、解析、响应和错误处理的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.为什么需要写一个tomcat

掌握Java Web应用程序的部署和管理技能。作为一名Java开发人员,我们需要将Java Web应用程序部署到Web服务器上进行运行和测试。掌握Tomcat的使用方法可以帮助我们更好地进行Java Web应用程序的部署和管理。

理解Web服务器的工作原理和技术架构。Tomcat作为一款Web服务器,它对于Java Web应用程序的运行有着重要的作用。学习Tomcat可以让我们更深入地理解Web服务器的工作原理和技术架构,这对于我们进行Web开发有着非常重要的意义。

学习Java Web应用程序的性能优化和调试技巧。在Java Web应用程序的开发过程中,我们经常需要对程序进行性能优化和调试。学习Tomcat可以帮助我们更好地掌握Java Web应用程序的性能优化和调试技巧,从而提高程序的运行效率和稳定性。

2.项目结构

3.效果演示

访问已存在的页面,这里举例说明用的是index.html

访问不存在的页面时,自动跳转到error.html页面

上述实现主要通过判断浏览器所请求的url中获取到请求信息,然后再进行判断请求信息在项目中是否存在,存在则进行响应,不存在则进行返回error.html

4.代码展示

 4.1 Tomcat类

public class Tomcat {
    public static void start() {
        MyServer myServer = new MyServer();
        myServer.receive();
    }

    public static void main(String[] args) {
        System.out.println("Server startup successfully");
        Tomcat.start();
    }
}

该文件主要的作用就是调用MyServer 中的receive方法进行启动自定义tomcat。

4.2 MyServer类

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServer {
    // 端口
    private int port = 8080;

    //接受浏览器请求方法
    public void receive() {
        try {
//            绑定相对应的端口信息
            ServerSocket serverSocket = new ServerSocket(port);
            while (true) {
                Socket socket = serverSocket.accept();
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();
                MyHttpRequest myHttpRequest = new MyHttpRequest(inputStream);
                myHttpRequest.parse();
                // 获取到请求路径
                String url = myHttpRequest.getUrl();
                System.out.println(url);
                // 判断请求路径中的数据是否存在
                MyHttpResponse response = new MyHttpResponse(outputStream);
                // 自己写一个成功的响应头
                String successHeader = "HTTP/1.1 200 OK\r\n" +
                        "Content-Type: text/html\r\n" +
                        "\r\n";
                outputStream.write(successHeader.getBytes());
                response.response(url);
                outputStream.flush();
                outputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

该类中主要就是定义Socket并绑定了相对应的端口(这里用的是8080端口),接受请求,并解析请求,响应请求头和数据。

4.3 MyHttpRequest类

import java.io.IOException;
import java.io.InputStream;

public class MyHttpRequest {
    private InputStream inputStream;

    private String url;
    public MyHttpRequest() {
    }

    public MyHttpRequest(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    public MyHttpRequest(InputStream inputStream, String url) {
        this.inputStream = inputStream;
        this.url = url;
    }

    /**
     * 获取
     * @return inputStream
     */
    public InputStream getInputStream() {
        return inputStream;
    }

    /**
     * 设置
     * @param inputStream
     */
    public void setInputStream(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    public String toString() {
        return "MyHttpRequest{inputStream = " + inputStream + "}";
    }

    public void parse(){
        byte[] bytes = new byte[1024];
        try {
            inputStream.read(bytes);
            String string = new String(bytes);
            String s = string.split(" ")[1];
            System.out.println(s);
            url = s;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取
     * @return url
     */
    public String getUrl() {
        return url;
    }

    /**
     * 设置
     * @param url
     */
    public void setUrl(String url) {
        this.url = url;
    }
}

该类主要的作用就是解析请求信息,返回资源信息的路径,通过多次调试查看其获取的请求资源中的信息,后通过split获取到了请求资源的路径信息。

4.4 MyHttpResponse类

import java.io.*;

public class MyHttpResponse {

    private OutputStream outputStream;

    private String url;

    private byte[] bytes = new byte[1024];

    public MyHttpResponse() {
    }

    public MyHttpResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    /**
     * 获取
     *
     * @return outputStream
     */
    public OutputStream getOutputStream() {
        return this.outputStream;
    }

    /**
     * 设置
     *
     * @param outputStream
     */
    public void setOutputStream(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    public String toString() {
        return "MyHttpResponse{outputStream = " + outputStream + "}";
    }

    public void response(String url) throws IOException {
        // 判断url是否存在
        System.out.println(System.getProperty("user.dir") + "/WebContent" + url);
        File urlFile = new File(System.getProperty("user.dir") + "/WebContent" + url);
        System.out.println("访问页面是否存在:" + urlFile.exists());
        if (urlFile.exists()) {
            System.out.println();
            FileInputStream inputStream = new FileInputStream(urlFile);
            int len = 0;
            System.out.println("开始响应...");
            while ((len = inputStream.read(bytes)) != -1) {
                getOutputStream().write(bytes, 0, len);
            }
            System.out.println("响应完成...");

        } else {
            // 判断url是否存在
            System.out.println("开始响应...");
            File errorFileUrl = new File(System.getProperty("user.dir") + "/WebContent" + "/error.html");
            FileInputStream errorFileInputStream = new FileInputStream(errorFileUrl);
            errorFileInputStream.read(bytes);
            getOutputStream().write(bytes, 0, 1024);
            System.out.println("响应完成...");
        }
    }

    public static void main(String[] args) throws IOException {
        MyHttpResponse response = new MyHttpResponse();
        response.response("/index.html");
    }

    /**
     * 获取
     *
     * @return url
     */
    public String getUrl() {
        return url;
    }

    /**
     * 设置
     *
     * @param url
     */
    public void setUrl(String url) {
        this.url = url;
    }

    /**
     * 获取
     *
     * @return bytes
     */
    public byte[] getBytes() {
        return bytes;
    }

    /**
     * 设置
     *
     * @param bytes
     */
    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }
}

该类中根据前文获取到的请求资源的路径信息,然后判断特定目录下是否存在该资源文件,若存在通过输入输出流,进行响应到浏览器,这里注意需要先响应请求头数据。若不存在,则响应错误页面到浏览器。

5.总结

        

手写一个Tomcat是一项非常复杂的任务,需要涉及到很多Java Web开发的知识和技术。下面是一个简单的手写Tomcat的总结:

  1. 理解Servlet规范:Tomcat实现了Servlet规范,因此我们需要了解Servlet规范的相关知识,包括Servlet接口、Servlet生命周期、请求响应流程等。

  2. 创建ServerSocket:Tomcat需要监听HTTP请求,因此我们需要创建一个ServerSocket对象,并设置端口号和最大连接数等参数。

  3. 解析HTTP请求:当有客户端发送HTTP请求时,我们需要解析请求头和请求体,获取请求方法、请求路径、请求参数等信息。

  4. 查找对应的Servlet:根据请求路径,我们需要查找对应的Servlet对象,如果没有找到,则返回404错误。

  5. 调用Servlet的service方法:找到对应的Servlet对象后,我们需要调用其service方法,处理请求并生成响应。

  6. 构造HTTP响应:在处理完请求后,我们需要根据响应内容,构造HTTP响应头和响应体,并将其返回客户端。

  7. 关闭Socket连接:当请求响应完成后,我们需要关闭Socket连接,释放资源。

总之,手写Tomcat是一项非常复杂的任务,需要掌握Java Web开发的相关知识和技术,包括Socket编程、HTTP协议、Servlet规范等。同时,也需要有耐心和细心,对每一个细节进行精细的调试和优化,才能实现一个高质量的Tomcat。

说说我本次实验中遇到的错误吧,就是成员变量与静态变量之间关系有点糊涂,一开始因为设置了成员变量类之间无法进行共享变量,还有就是进行响应页面时,没有设置请求头信息无法获取到资源信息,总的来说学习还是不错的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值