tomcat到底是啥?手写一个tomcat带你理解它的机制和原理!

手写 minitomcat

目标:可以通过浏览器客户端发送 http 请求,minicat 可以接受请求并进行处理,处理后的结果可以返回给客户端。

  • 接受请求,socket 通信
  • 请求信息封装成 Request 对象,返回的信息封装成 Response 对象
  • 客户端请求资源,分为静态资源和动态资源
  • 资源返回给浏览器

好吧稍微有点标题党,不过对于理解tomcat的原理机制,这样一个mini版的tomcat自己写出来,还是很有帮助的,话不多说,进入正题。

1.0版本

需求:请求 8080 端口,固定返回字符串。

创建 BootStrap 类
端口号暂时写死 8080,编写 start 方法,监听端口,获取请求,返回资源。
通过 main 方法启动,代码如下:

public class BootStrap {
   
    //定义 socket 监听端口号(写死)
    private int port = 8080;

    public int getPort() {
   
        return port;
    }

    public void setPort(int port) {
   
        this.port = port;
    }

    /**
     * 初始化操作
     */
    public void start() throws IOException {
   
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("-------->mini-tomcat start on port: " + port);
        while (true){
   
            Socket accept = serverSocket.accept();
            OutputStream outputStream = accept.getOutputStream();
            outputStream.write("Hello mini-tomcat!".getBytes());
            accept.close();
        }
    }

    //程序入口
    public static void main(String[] args) {
   
        BootStrap bootStrap = new BootStrap();
        try {
   
            bootStrap.start();
        } catch (IOException e) {
   
            e.printStackTrace();
        }

    }
}

什么?太简单了?
但你会发现,此时浏览器访问,并不能实现这个功能,因为返回信息的时候,我们没有按照 http 的规范,浏览器无法识别。
增加一个 httpProtocolUtil 类
封装返回信息

/**
 * http 协议工具类
 * 提供响应头信息。只提供 200 和 404 即可
 */
public class HttpProtocolUtil {
   
    public static String getHttpHeader200(long contentLength) {
   
        return "HTTP/1.1 200 OK \n" +
                "Content-Type: text/html \n" +
                "Content-Lenght: " + contentLength + " \n" +
                "\r\n";
    }

    public static String getHttpHeader404() {
   
        String str404 = "<h1>404 not found</h1>";
        return "HTTP/1.1 404 NOT Found \n" +
                "Content-Type: text/html \n" +
                "Content-Lenght: " + str404.getBytes().length + " \n" +
                "\r\n" + str404;
    }
}

再改造之前的 start 方法

while (true){
   
    Socket accept = serverSocket.accept();
    OutputStream outputStream = accept.getOutputStream();
    String responseText = HttpProtocolUtil.getHttpHeader200("Hello mini-tomcat!".getBytes().length)+"Hello mini-tomcat!";
    outputStream.write(responseText.getBytes());
    accept.close();
}

再次访问 localhost:8080
bingo~成功
在这里插入图片描述
容易吧,不过这只是入门版本而已,太low了,返回的内容都是固定的,看上去好像也没什么技术含量,不着急,2.0版本马上来~

2.0版本

需求:通过发送请求,返回静态资源。
首先。我们先弄清楚,浏览器发请求过来,到底发了一些什么东西?
在后台的逻辑中,先获取请求内容进行控制台打印,看看请求的信息都有是什么,代码如下:

//2.0 版本
while (true){
   
    Socket accept = serverSocket.accept();
    InputStream inputStream = accept.getInputStream();
    int count = 0;
    while (count == 0){
   
        count = inputStream.available();
    }
    byte[] bytes = new byte[count];
    inputStream.read(bytes);
    System.out.println("------>请求信息:"+ new String(bytes));

    OutputStream outputStream = accept.getOutputStream();
    accept.close();
}

执行,发送请求 localhost:8080
发现后台打印的是这样:
在这里插入图片描述
这么复杂?其实我们要关注的就只是第一行而已:
在这里插入图片描述
没错,这里的GET代表请求方式是GET请求,第二个斜杠“/”代表的就是访问路径了,因为我们请求地址后边什么都没有,所以这里就只有一个“/”,不信,你可以试试请求localhost:8080/index.html 看看后台打印出来的是不是 /index.html 请自行实验~
所以,接下来,我们对请求信息进行解析,封装成一个我们需要的对象:

Request request = new Request(inputStream);

这样把请求url封装到request对象里,需要的时候取就可以了。
Request类的定义如下

/**
 * 把请求信息封装为Request对象(根据InputSteam输入流封装)
 */
public class Request {
   

    private String method; // 请求方式,比如GET/POST
    private String url;  // 例如 /,/index.html

    private InputStream inputStream;  // 输入流,其他属性从输入流中解析出来

    public String getMethod() {
   
        return method;
    }

    public void setMethod(String method) {
   
        this.method = method;
    }

    public String getUrl() {
   
        return url;
    }

    public void setUrl(String url) {
   
        this.url = url;
    }

    public InputStream getInputStream() {
   
        return inputStream;
    }

    public void setInputStream(InputStream inputStream) {
   
        this.inputStream = inputStream;
    }

    public Request() {
   
    }


    // 构造器,输入流传入
    public Request(InputStream inputStream) throws IOException {
   
        this.inputStream = inputStream;

        // 从输入流中获取请求信息
        int count = 0;
        while (count == 0) {
   
            count = inputStream.available();
        }

        byte[] bytes = new byte[count];
        inputStream.read(bytes)
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值