模拟一个简单的tomcat
简单处理
// 客户端和服务器的通信,说到底就是两个数据的传输,
// 客户端发送inputStream给服务器,服务器回复
// outputStream给客户端。
public class TomcatServerV1 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
while (true) {//一直监听,直到受到停止的命令
Socket socket = null;
try {
socket = serverSocket.accept();//如果没有请求,会一直hold在这里等待,有客户端请求的时候才会继续往下执行
// log
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//获取输入流(请求)
StringBuilder stringBuilder = new StringBuilder();
String line = null;
while ((line = bufferedReader.readLine()) != null && !line.equals("")) {//得到请求的内容,注意这里作两个判断非空和""都要,只判断null会有问题
stringBuilder.append(line).append("<br>");
}
String result = stringBuilder.toString();
System.out.println(result);
// echo
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);//这里第二个参数表示自动刷新缓存
printWriter.println("HTTP/1.1 200 OK");
printWriter.println("Content-Type:text/html;charset=utf-8");
printWriter.println();
printWriter.println("<h5>你刚才发送的请求数据是:<br>");
printWriter.write(result);//将日志输出到浏览器
printWriter.println("</h5>");
// release
printWriter.close();
bufferedReader.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

每个请求一个线程
class RequestHandler implements Runnable{
private Socket socket;
public RequestHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// log
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//获取输入流(请求)
StringBuilder stringBuilder = new StringBuilder();
String line = null;
while ((line = bufferedReader.readLine()) != null && !line.equals("")) {
stringBuilder.append(line).append("<br>");
}
String result = stringBuilder.toString();
System.out.println(result);
// echo
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);//这里第二个参数表示自动刷新缓存
printWriter.println("HTTP/1.1 200 OK");
printWriter.println("Content-Type:text/html;charset=utf-8");
printWriter.println();
printWriter.println("<h5>你刚才发送的请求数据是:<br>");
printWriter.write(result);//将日志输出到浏览器
printWriter.println("</h5>");
// release
printWriter.close();
bufferedReader.close();
socket.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
public class TomcatServerV2 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {//一直监听,直到受到停止的命令
Socket socket = null;
socket = serverSocket.accept();//如果没有请求,会一直hold在这里等待,有客户端请求的时候才会继续往下执行
RequestHandler requestHandler = new RequestHandler(socket);
new Thread(requestHandler).start();
}
}
}
模拟tomcat
正如前面的博客:Servlet笔记中记录:

首先建一个MyServlet接口,然后创建一个抽象类MyHttpServlet继承接口,最后建一个UserServlet实现具体的doGet,doPost等方法。
pom依赖添加servlet和dom4j。DOM4J是dom4j.org出品的一个开源XML解析包。
项目目录:

原理图:

Request.java
package cn.orzlinux.Bean.mytomcat.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Request {
// 如/usr
private String uri;
// 请求方法
private String method;
public Request(InputStream inputStream) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader((inputStream)));
//取HTTP请求响应的第一行,GET /user HTTP/1.1,按空格隔开
String[] data = reader.readLine().split(" ");
this.uri = data[1];
this.method = data[0];
} catch (IOException e) {
e.printStackTrace();
}
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
}
response
package cn.orzlinux.Bean.mytomcat.http;
import java.io.OutputStream;
public class Response {
public OutputStream outputStream;
public static final String responsebody="HTTP/1.1 200+\r\n"+"Content-Type:text/html+\r\n"
+"\r\n";
public Response(OutputStream outputStream){
this.outputStream=outputStream;
}
}
MyServlet
package cn.orzlinux.Bean.mytomcat.servlet;
import cn.orzlinux.Bean.mytomcat.http.Request;
import cn.orzlinux.Bean.mytomcat.http.Response;
public interface MyServlet {
void init() throws Exception;
void service(Request request, Response response) throws Exception;
void destroy();
}
MyHttpServlet
package cn.orzlinux.Bean.mytomcat.servlet;
import cn.orzlinux.Bean.mytomcat.http.Request;
import cn.orzlinux.Bean.mytomcat.http.Response;
public abstract class MyHttpServlet implements MyServlet {
public void init() throws Exception {
}
public void service(Request request, Response response) throws Exception {
if("get".equalsIgnoreCase(request.getMethod())) {
this.doGet(request,response);
} else {
this.doPost(request,response);
}
}
public abstract void doGet(Request request,Response response);
public abstract void doPost(Request request,Response response);
public void destroy() {
}
}
userServlet
package cn.orzlinux.Bean.mytomcat.servlet;
import cn.orzlinux.Bean.mytomcat.http.Request;
import cn.orzlinux.Bean.mytomcat.http.Response;
import java.io.IOException;
import java.io.OutputStream;
public class UserServlet extends MyHttpServlet {
public void doGet(Request request, Response response) {
System.out.println("doget");
this.doPost(request,response);
}
public void doPost(Request request, Response response){
OutputStream outputStream = response.outputStream;
String result = Response.responsebody+"user handle successful";
try {
outputStream.write(result.getBytes());
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
RequestHandler
package cn.orzlinux.Bean.mytomcat.socket;
import cn.orzlinux.Bean.mytomcat.http.Request;
import cn.orzlinux.Bean.mytomcat.http.Response;
import cn.orzlinux.Bean.mytomcat.servlet.MyHttpServlet;
import java.io.*;
import java.net.Socket;
public class RequestHandler implements Runnable{
private Socket socket;
public RequestHandler(Socket socket) {
this.socket = socket;
}
public void run() {
// log
try {
Request request = new Request(socket.getInputStream());
Response response = new Response(socket.getOutputStream());
String uri = request.getUri();
System.out.println(uri);
String servletName = TomcatServerV3.urlmapping.get(uri);
MyHttpServlet servlet = TomcatServerV3.servletMapping.get(servletName);
if(servlet!=null) {
servlet.service(request,response);
}else{
String resp=Response.responsebody+"can not find servlet";
OutputStream outputStream=socket.getOutputStream();
System.out.println(resp);
outputStream.write(resp.getBytes());
outputStream.flush();
outputStream.close();
}
}catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
TomcatServerV3
package cn.orzlinux.Bean.mytomcat.socket;
import cn.orzlinux.Bean.mytomcat.servlet.MyHttpServlet;
import cn.orzlinux.Bean.mytomcat.socket.RequestHandler;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
public class TomcatServerV3 {
public static final int port = 8080;
// 定义mytomcat.xml中的两个映射
public static final HashMap<string, myhttpservlet=""> servletMapping = new HashMap<string, myhttpservlet="">();
public static final HashMap<string,string> urlmapping=new HashMap<string, string="">();
public static void main(String[] args) throws IOException {
TomcatServerV3 tomcatServerV3 = new TomcatServerV3();
tomcatServerV3.init();
tomcatServerV3.run();
}
// 初始化,加载xml里面的servlet信息
private void init() {
try {
String path = TomcatServerV3.class.getResource("/").getPath();
SAXReader reader = new SAXReader();
Document document = reader.read(new File(path+"mytomcat.xml"));
Element rootelement = document.getRootElement();
List<element> elements = rootelement.elements();
for(Element element:elements) {
if ("servlet".equalsIgnoreCase(element.getName())){
Element servletname=element.element("servlet-name");
Element servletclass=element.element("servlet-class");
System.out.println(servletname.getText()+"==>"+servletclass.getText());
//需要注意的是servletMapping映射的第二个参数,要通过反射的方式进行实例化
servletMapping.put(servletname.getText(),
(MyHttpServlet) Class.forName(servletclass.getText().trim()).newInstance());
}else if ("servlet-mapping".equalsIgnoreCase(element.getName())){
Element servletname=element.element("servlet-name");
Element urlpattern=element.element("url-pattern");
System.out.println(servletname.getText()+"==>"+urlpattern.getText());
urlmapping.put(urlpattern.getText(),servletname.getText());
}
}
}catch (Exception e) {
e.printStackTrace();
}
}
private void run() {
ServerSocket serverSocket= null;
try {
serverSocket = new ServerSocket(port);
System.out.println("====服务启动====");
while(!serverSocket.isClosed()){
Socket socket=serverSocket.accept();
RequestHandler requestHandler=new RequestHandler(socket);
new Thread(requestHandler).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出:
userServlet==>cn.orzlinux.Bean.mytomcat.servlet.UserServlet
userServlet==>/user
====服务启动====
/
HTTP/1.1 200+
Content-Type:text/html+
can not find servlet
/user
doget

最后再回顾一下原理图:

参考
从零开始手写Tomcat,一文彻底搞懂Tomcat运行流程(附源码)
本文同步发布于orzlinux.cn
模拟一个简单的tomcat的更多相关文章
- 实现一个简单的Tomcat
实现一个简单的Tomcat 1. Tomcat作用 我们的web应用会运行在Tomcat中,那么显然请求必定是先到达Tomcat的,Tomcat对于请求实际上会进行如下的处理: 提供Socket服务: ...
- 自己模拟的一个简单的tomcat
servlet容器的职责 总的来说,一个全功能的servlet容器会为servlet的每个HTTP请求做下面的一些工作: 1,当第一次调用servlet的时候,加载该servlet类并调用servle ...
- 理解与模拟一个简单web服务器
先简单说下几个概念,根据自己的理解,不正确请见谅. web服务器 首先要知道什么是web服务器,简单说web服务器就是可以使用HTTP传输协议与客户端进行通信的服务器.最初的web服务器只能用来处理静 ...
- 使用Socket模拟一个简单的Webservice调用
webservice是对socket的一个封装,让远程调用调用变得更加简单,那么使用socket究竟有多么麻烦呢?来看看. 做一个简单的天气查询: 服务端: public class SocketSe ...
- 模拟一个简单的基于tcp的远程关机程序(转)
最近在学习unix网络编程,现在正在学习tcp的通信.其实,只要建立起了tcp通信,操作远端的计算机就不是什么问题了.正向telnet一样,也是基于tcp/IP协议的.所以这个实验,也算是对telne ...
- 理解与模拟一个简单servlet容器
servlet接口 使用servlet编程需要实现或者继承实现了javax.servlet.Servlet接口的类,其中定义了5个签名方法: public void init(ServletConfi ...
- java模拟一个简单的QQ
v 项目源码 https://github.com/hjzgg/java_QQ v 标题效果 package testFour; import java.awt.Color; import ...
- Antd组件库,利用Menu组件模拟一个简单Tree组件
当前工作中,前端的主要技术栈用是vue. 那React怎么办呢?总不至于把他扔在墙角吧! 只能在一些很小的项目上,也只有自己一个前端的时候,悄悄的上React. 当然,React项目UI组件还是最喜欢 ...
- Android中用URL模拟一个简单的图片加载器
首先,需要添加权限. <uses-permission android:name="android.permission.INTERNET"/> 整体代码如下: pac ...
随机推荐
- vs2019 实现C#调用c++的dll两种方法
1.托管与非托管的区别 2.非托管类的实现 第一步:创建C++空项目(命名Caculate)添加一个类AddOperate 第二步:将C++代码编译成动态库dll 第三步:将dll拷贝到c#项目输入目 ...
- 使用dom4j工具:设置输出格式compactFormat和PrettyPrint(六)
package dom4j_write; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStre ...
- Flink的状态管理与恢复机制
参考地址:https://www.cnblogs.com/airnew/p/9544683.html 问题一.什么是状态? 问题二.Flink状态类型有哪几种? 问题三.状态有什么作用? 问题四.如何 ...
- LVS本地实验环境搭建
文中实验需要使用以下软件: CentOS的镜像 Virtual Box GNS3 0.实验前的准备工作 0.1.修改yum源 为了方便安装软件,我们设置yum源为公司yum源 1.直接复制公司机器上的 ...
- tensorflow summary demo with linear-model
tf.summary + tensorboard 用来把graph图中的相关信息,如结构图.学习率.准确率.Loss等数据,写入到本地硬盘,并通过浏览器可视化之. 整理的代码如下: import te ...
- 用XPath定位Web页面元素时,如何快速验证XPath语句是否正确?
在使用Selenium做Web UI自动化测试的过程中,XPath是一种定位页面元素的常用方式.然而,面对某些元素的XPath路径过于复杂,我们想快速验证拼凑的Xpath语句是否正确时,该怎么办呢?这 ...
- WEB漏洞——SQL
由于我的博客是学到渗透的时候才做的,没有关于WEB漏洞的笔记,现在发现WEB层面的漏洞有些不太熟悉了,边写一下笔记边复习一下,就从sql注入开始吧 话不多说先上大佬写的表[ctfhub]SQL注入 - ...
- python 并行计算
一.进程和线程 原文链接:https://zhuanlan.zhihu.com/p/356220352 进程是分配资源的最小单位,线程是系统调度的最小单位.当应用程序运行时最少会开启一个进程,此时计算 ...
- 20210811 Dove 打扑克,Cicada 与排序,Cicada 拿衣服
考场 开考感觉 T3 比较可做.T1 看上去不难但毫无思路. 先想了 25min T3,想到一个确定左端点,二分最长的右端点,甚至想到了用猫树维护区间 or and...上厕所回来发现假了,没有单调性 ...
- Selenium系列(十八) - Web UI 自动化基础实战(5)
如果你还想从头学起Selenium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1680176.html 其次,如果你不懂前端基础知识, ...