tomcat原理解析(一):一个简单的实现

article/2025/9/14 0:47:22

一 概述

       前段时间去面试,被人问到了tomcat实现原理。由于平时没怎么关注容器的实现细节,这个问题基本没回答上来。所以最近花了很多时间一直在网上找资料和看tomcat的源码来研究里面处理一个HTTP请求的流程。网上讲tomcat的帖子比较多,大多都是直接切入主题看其源码,从我个人感受来说直接研究其源码实现比较难理解和非常枯燥,需要由简到难,慢慢深入。

二  一个简单tomcat服务器实现

        tomat是一个servlet容器,来处理http请求。在平时的使用中我们都会再浏览器中输入http地址来访问服务资源,比如格式http://host[":"port][abs_path]。从浏览器到服务端的一次请求都遵循http协议,在网络上其实走仍然是tcp协议,即我们常使用的socket来处理客户端和服务器的交互。根据输入的http地址可以知道服务器的IP地址和端口,根据这两个参数就可以定位到服务器的唯一地址。tomcat根据http地址端口后面的资源路径就可以知道反馈什么样的资源给浏览器。下面给出了一个非常简单的代码模拟了tomcat的简单实现


package com;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.StringTokenizer;public class TomcatServer {private final static int PORT = 8080;public static void main(String[] args) {try {ServerSocket server = new ServerSocket(PORT);//根据端口号启动一个serverSocketServletHandler servletHandler=new ServletHandler(server);servletHandler.start();} catch (Exception e) {e.printStackTrace();}}private static class ServletHandler extends Thread{ServerSocket server=null;public ServletHandler(ServerSocket server){this.server=server;}@Overridepublic void run() {while (true) {try {Socket client = null;client = server.accept();//ServerSocket阻塞等待客户端请求数据if (client != null) {try {System.out.println("接收到一个客户端的请求");//根据客户端的Socket对象获取输入流对象。//封装字节流到字符流BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));// GET /test.jpg /HTTP1.1//http请求由三部分组成,分别是:请求行、消息报头、请求正文。//这里取的第一行数据就是请求行。http协议详解可以参考http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html说的很详细String line = reader.readLine();System.out.println("line: " + line);//拆分http请求路径,取http需要请求的资源完整路径String resource = line.substring(line.indexOf('/'),line.lastIndexOf('/') - 5);System.out.println("the resource you request is: "+ resource);resource = URLDecoder.decode(resource, "UTF-8");//获取到这次请求的方法类型,比如get或post请求String method = new StringTokenizer(line).nextElement().toString();System.out.println("the request method you send is: "+ method);//继续循环读取浏览器客户端发出的一行一行的数据while ((line = reader.readLine()) != null) {if (line.equals("")) {//当line等于空行的时候标志Header消息结束break;}System.out.println("the Http Header is : " + line);}//如果是POST的请求,直接打印POST提交上来的数据if ("post".equals(method.toLowerCase())) {System.out.println("the post request body is: "+ reader.readLine());}else if("get".equals(method.toLowerCase())){//判断是get类型的http请求处理//根据http请求的资源后缀名来确定返回数据//比如下载一个图片文件,我这里直接给定一个图片路径来模拟下载的情况if (resource.endsWith(".jpg")) {transferFileHandle("d://123.jpg", client);closeSocket(client);continue;} else {//直接返回一个网页数据//其实就是将html的代码以字节流的形式写到IO中反馈给客户端浏览器。//浏览器会根据http报文“Content-Type”来知道反馈给浏览器的数据是什么格式的,并进行什么样的处理PrintStream writer = new PrintStream(client.getOutputStream(), true);writer.println("HTTP/1.0 200 OK");// 返回应答消息,并结束应答writer.println("Content-Type:text/html;charset=utf-8");writer.println();//writer.println("Content-Length:" + html.getBytes().length);// 返回内容字节数writer.println("<html><body>");writer.println("<a href='www.baidu.com'>百度</a>");writer.println("<img src='https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png'></img>");writer.println("</html></body>");//writer.println("HTTP/1.0 404 Not found");// 返回应答消息,并结束应答writer.println();// 根据 HTTP 协议, 空行将结束头信息writer.close();closeSocket(client);//请求资源处理完毕,关闭socket链接continue;}}} catch (Exception e) {System.out.println("HTTP服务器错误:"+ e.getLocalizedMessage());}}} catch (Exception e) {e.printStackTrace();}}}private void closeSocket(Socket socket) {try {socket.close();} catch (IOException ex) {ex.printStackTrace();}System.out.println(socket + "离开了HTTP服务器");}private void transferFileHandle(String path, Socket client) {File fileToSend = new File(path);if (fileToSend.exists() && !fileToSend.isDirectory()) {try {//根据Socket获取输出流对象,将访问的资源数据写入到输出流中PrintStream writer = new PrintStream(client.getOutputStream());writer.println("HTTP/1.0 200 OK");// 返回应答消息,并结束应答writer.println("Content-Type:application/binary");writer.println("Content-Length:" + fileToSend.length());// 返回内容字节数writer.println();// 根据 HTTP 协议, 空行将结束头信息FileInputStream fis = new FileInputStream(fileToSend);byte[] buf = new byte[fis.available()];fis.read(buf);writer.write(buf);writer.close();fis.close();} catch (IOException e) {e.printStackTrace();}}}}}


三  实践

    1.在浏览器中输入http://localhost:8080/123.jpg 链接,可以看到浏览器里面就将123.jpg下载到本地了。

    2.在浏览器中输入一个服务器不能识别的请求后缀比如http://localhost:8080/123.jpg1,可以看到浏览器打开了一个网页。如下图:点击里面的百度链接可以跳转

    3.后台tomcat服务器打印的http请求报文

      接收到一个客户端的请求
line: GET /123.jpg1 HTTP/1.1
the resource you request is: /123.jpg1
the request method you send is: GET
the Http Header is : Host: localhost:8080
the Http Header is : Connection: keep-alive
the Http Header is : Pragma: no-cache
the Http Header is : Cache-Control: no-cache
the Http Header is : Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
the Http Header is : Upgrade-Insecure-Requests: 1
the Http Header is : User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36
the Http Header is : Accept-Encoding: gzip, deflate, sdch
the Http Header is : Accept-Language: zh-CN,zh;q=0.8
Socket[addr=/0:0:0:0:0:0:0:1,port=57864,localport=8080]离开了HTTP服务器

四  总结

从整个代码和测试情况来看,一次http请求其实就是一次socket套接字的处理。浏览器发起scoket的请求,tomcat服务器接受请求,并根据请求的路径定位客户端需要访问的资源。  只是socket客户端和服务器数据在交互时,都遵守着http协议规范。当然真正的tomcat容器比这个demo实现要复杂的很多,这个简易的tomcat服务器能够帮我们更好的理解tomcat源码。




http://chatgpt.dhexx.cn/article/iul2EtNB.shtml

相关文章

Tomcat工作原理之运行机制

一、Tomcat运行原理分析1.Tomcat是运行在JVM中的一个进程。它定义为【中间件】&#xff0c;顾名思义&#xff0c;是一个在Java项目与JVM之间的中间容器。 2.Web项目的本质&#xff0c;是一大堆的资源文件和方法。Web项目没有入口方法(main方法)&#xff0c;&#xff0c;意味着…

tomcat 工作原理

大致的架构是 jsptomcatmysql&#xff0c;记录tomcat学习一点笔记。 Tomcat是Servlet运行环境&#xff08;容器&#xff09;&#xff0c;每个servlet执行init(),service(),destory() 以下是servlet的作用 Servlet的调用 Tomcat的工作模式3种&#xff1a;独立Servlet&#xff0c…

Tomcat的原理及架构

转自&#xff1a;https://zhuanlan.zhihu.com/p/35398064 俗话说&#xff0c;站在巨人的肩膀上看世界&#xff0c;一般学习的时候也是先总览一下整体&#xff0c;然后逐个部分个个击破&#xff0c;最后形成思路&#xff0c;了解具体细节&#xff0c;Tomcat的结构很复杂&#xf…

Tomcat基本原理

1.Tomcat核心&#xff1a; Http服务器Servlet容器 组件分工&#xff1a; 连接器Connector&#xff1a;处理 Socket 连接&#xff0c;负责网络字节流与 Request 和 Response 对象的转化。容器Container&#xff1a;加载和管理 Servlet&#xff0c;以及具体处理 Request 请求。 …

tomcat的工作原理

本文源自转载&#xff1a;你还记得 Tomcat 的工作原理么 一、Tomcat 整体架构 Tomcat 是一个免费的、开源的、轻量级的 Web 应用服务器。适合在并发量不是很高的中小企业项目中使用。 二、文件目录结构 以下是 Tomcat 8 主要目录结构 三、功能组件结构 Tomcat 的核心功能有…

Tomcat原理整理

目录接口 功能组件 Tomcat 的核心功能有两个&#xff0c;分别是负责接收和反馈外部请求的连接器 Connector&#xff0c;和负责处理请求的容器 Container。其中连接器和容器相辅相成&#xff0c;多个 Connector 和一个 Container 一起构成了基本的 web 服务 Service。每个 Serve…

Tomcat工作原理详细介绍

大部分企业的 Web 应用都运行在它上面&#xff0c;Tomcat 对于程序员来说算是老朋友了&#xff0c;那么今天带大家走近这位老朋友&#xff0c;看看它是如何处理 Web 请求&#xff0c;以及它内部的体系结构&#xff0c;这对帮助我们理解 Tomcat 的使用大有益处。 本文你将会学会…

Tomcat原理

Tomcat顶层架构 Tomcat的顶层结构图&#xff1a; 1、Tomcat中最顶层的容器是Server&#xff0c;代表着整个服务器&#xff0c;一个Server可以包含至少一个Service&#xff0c;用于具体提供服务。 2、Service主要包含两个部分&#xff1a;Connector和Container。 Tomcat 的心脏…

javascript 文本框限制输入1到10位数字正则表达式

<meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <!DOCTYPE html> <html> <head><title>DOM 教程</title><style></style><!--不需要再次引用jquery--><script type"te…

js数字正则

js正则表达式 1.了解什么是正则表达式&#xff1f; 正则表达式&#xff08;Regular Expression&#xff09;又称规则表达式&#xff0c;简单来说它就是一个概念&#xff0c;用事先声明好的字符和字符的组合&#xff0c;来组成一个“规则字符串”&#xff0c;用来检测我们书写…

卷积神经网络降维方法,深度神经网络降维方法

1、卷积神经网络中用1*1 卷积有什么作用或者好处 1*1卷积的主要作用有以下几点&#xff1a; 1、降维&#xff08; dimension reductionality &#xff09;。比如&#xff0c;一张500 * 500且厚度depth为100 的图片在20个filter上做1*1的卷积&#xff0c;那么结果的大小为500*5…

常用降维方法

降维方法分为线性核非线性降维&#xff0c;非线性降维又分为基于核函数和基于特征值的方法。 线性降维方法&#xff1a;PCA ICA LDA LFA LPP(LE的线性表示) 基于核函数的非线性降维方法&#xff1a;KPCA KICA KDA 基于特征值的非线性降维方法&#xff08;流型学习&#x…

机器学习四大数据降维方法详解

引言&#xff1a; 机器学习领域中所谓的降维就是指采用某种映射方法&#xff0c;将原高维空间中的数据点映射到低维度的空间中。降维的本质是学习一个映射函数 f : x->y&#xff0c;其中x是原始数据点的表达&#xff0c;目前最多使用向量表达形式。 y是数据点映射后的低维向…

机器学习 | 降维问题

目录 一、主成分分析 二、奇异值分解 2.1 奇异值分解原理 2.2 奇异值分解实践 三、特征值与特征向量 一、主成分分析 主成分有如下特征&#xff1a; 每个主成分是原变量的线性组合&#xff1b;各个主成分之间互不相关&#xff1b;主成分按照方差贡献率从大到小依次排列&…

数据降维方法总结

Introduce 经过这几天面试后&#xff0c;我发现数据降维这一块在工业界用的很多或者说必不可少&#xff0c;因此&#xff0c;这方面需要重点关注。今天&#xff0c;我将数据降维总结于此&#xff0c;包括他人成果&#xff0c;这里对他们的内容表示感谢。 Method 对数据降维作…

机器学习四大降维方法

引言&#xff1a; 机器学习领域中所谓的降维就是指采用某种映射方法&#xff0c;将原高维空间中的数据点映射到低维度的空间中。降维的本质是学习一个映射函数 f : x->y&#xff0c;其中x是原始数据点的表达&#xff0c;目前最多使用向量表达形式。 y是数据点映射后的低维向…

机器学习降维方法概括

最近刷题看到特征降维相关试题&#xff0c;发现自己了解的真是太少啦&#xff0c;只知道最简单的降维方法&#xff0c;这里列出了常见的降维方法&#xff0c;有些算法并没有详细推导。特征降维方法包括&#xff1a;Lasso&#xff0c;PCA&#xff0c;小波分析&#xff0c;LDA&am…

详解机器学习高维数据降维方法

当特征选择完成后&#xff0c;可以直接训练模型了&#xff0c;但是可能由于特征矩阵过大&#xff0c;导致计算量大&#xff0c;训练时间长的问题&#xff0c;因此降低维度也是必不可少的。 常见的降维方法除了以上提到的基于 L1 惩罚项的模型以外&#xff0c;另外还有主成分分…

机器学习之降维

本周关于降维的学习主要分为五类&#xff1a;PCA、LDA、LLE、tSNE、ISOMAP 来进行学习 首先自己的任务是&#xff1a;tSNE的学习 &#xff08;一&#xff09;降维的基本知识点总结 1、降维方法分为线性和非线性降维&#xff0c;非线性降维又分为基于核函数和基于特征值的方…

四大机器学习降维方法

引言&#xff1a; 机器学习领域中所谓的降维就是指采用某种映射方法&#xff0c;将原高维空间中的数据点映射到低维度的空间中。降维的本质是学习一个映射函数 f : x->y&#xff0c;其中x是原始数据点的表达&#xff0c;目前最多使用向量表达形式。 y是数据点映射后的低维向…