> 文章列表 > 手写Tomcat源码简易篇

手写Tomcat源码简易篇

手写Tomcat源码简易篇

Http协议

HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP)。

HTTP协议的主要特点:

1、支持客户/服务器模式。

2、简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

3、灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

4、无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

5、无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTPS协议的主要特点:

1、内容加密:采用混合加密技术,中间者无法直接查看明文内容

2、验证身份:通过证书认证客户端访问的是自己的服务器

3、保护数据完整性:防止传输的内容被中间人冒充或者篡改

4、SSL证书需要购买申请,功能越强大的证书费用越高

5、SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗

6、HTTPS连接缓存不如HTTP高效,流量成本高

7、HTTPS协议握手阶段比较费时,对网站的响应速度有影响,影响用户体验。

Http协议的组成部分 

这里在手写tomcat源码的时候用到对于http协议的解析,所以将http协议的组成如图所示,在源码中对于http协议的解析也是按照如图格式来解析的。

 模拟源码

Tomcat组件

  • Server:
    服务器,用来接收其他计算机(客户端)发来的请求数据并进行解析,完成相关业务处理,然后将处理结果返回给计算机。
  • Service:
    Web服务,表示动作状态。
  • Servlet:
    应用程序、服务程序。
  • Connector:
    连接器,用于接收请求并最终将请求返回给客户端。
  • Container:
    容器,包含下面要讲到的Engine、Context、Host、Wrapper。
  • Engine:
    引擎,负责请求 的处理。
  • Context:
    上下文容器,也可以看成Web应用。
  • Host:
    虚拟主机。
  • Wrapper:
    封装器,代表一个Servlet。

目录结构

tomcat类

直接执行tomcat类中的main方法,然后在浏览器中访问任意本地8080端口就可以实现页面的输出。这里仅仅是在浏览器页面上打印hello这个英文单词。进行简易的代码模拟实现。

public class tomcat {public void start(){try {ExecutorService executorService = Executors.newFixedThreadPool(8);ServerSocket serverSocket = new ServerSocket(8080);while (true) {Socket accept = serverSocket.accept();executorService.execute(new SocketProcessor(accept));}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {tomcat tomcat=new tomcat();tomcat.start();}
}

Request类,多余的实现类在这里删除了,源代码运行要实现。

public class Request implements HttpServletRequest {private String method;private String url;private String protocol;private Socket socket;public Socket getSocket() {return socket;}public Request(String method, String url, String protocol, Socket socket) {this.method = method;this.url = url;this.protocol = protocol;this.socket=socket;}public String getMethod() {return method;}public StringBuffer getRequestURL() {return new StringBuffer(url);}public String getProtocol() {return protocol;}}

Response类

public class Response implements HttpServletResponse {private int status=200;private String message="ok";private Map<String,String> headers=new HashMap<>();private Request request;private OutputStream socketOutputStream;private byte SP=' ';private byte CR='\\r';private byte LF='\\n';private ResponseServletOutputStream responseServletOutputStream=new ResponseServletOutputStream();public Response(Request request) {this.request = request;try {this.socketOutputStream=request.getSocket().getOutputStream();} catch (IOException e) {e.printStackTrace();}}public void complete(){try {sendResponseLine();} catch (IOException e) {e.printStackTrace();}try {sendResponseHeader();} catch (IOException e) {e.printStackTrace();}try {sendResponseBody();} catch (IOException e) {e.printStackTrace();}}private void sendResponseBody() throws IOException {socketOutputStream.write(getOutputStream().getBytes());}private void sendResponseHeader() throws IOException {for (Map.Entry<String, String> stringStringEntry : headers.entrySet()) {String key=stringStringEntry.getKey();String value=stringStringEntry.getValue();socketOutputStream.write(key.getBytes());socketOutputStream.write(":".getBytes());socketOutputStream.write(value.getBytes());socketOutputStream.write(CR);socketOutputStream.write(LF);}socketOutputStream.write(CR);socketOutputStream.write(LF);}private void sendResponseLine() throws IOException {socketOutputStream.write(request.getProtocol().getBytes());socketOutputStream.write(SP);socketOutputStream.write(status);socketOutputStream.write(SP);socketOutputStream.write(message.getBytes());socketOutputStream.write(CR);socketOutputStream.write(LF);}@Overridepublic void addHeader(String s, String s1) {headers.put(s,s1);}@Overridepublic void setStatus(int i, String s) {status=i;message=s;}@Overridepublic int getStatus() {return status;}@Overridepublic ResponseServletOutputStream getOutputStream() throws IOException {return responseServletOutputStream;}}

MyServlet类

public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println(req.getMethod());resp.addHeader("Content-Length","5");resp.addHeader("Content-Type","text/plain;charset=utf-8");resp.getOutputStream().write("hello".getBytes());}
}

SocketProcess类

public class SocketProcessor implements Runnable{private Socket socket;public SocketProcessor(Socket socket) {this.socket = socket;}@Overridepublic void run() {processSocket(socket);}private void processSocket(Socket socket) {try {InputStream inputStream = socket.getInputStream();byte[] bytes = new byte[1024];inputStream.read(bytes);int pos=0;int begin=0,end=0;for(;pos<bytes.length;pos++,end++){if(bytes[pos]==' ')break;}StringBuilder method=new StringBuilder();for(;begin<end;begin++){method.append((char)bytes[begin]);}pos++;begin++;end++;for(;pos<bytes.length;pos++,end++){if(bytes[pos]==' ')break;}StringBuilder url=new StringBuilder();for(;begin<end;begin++){url.append((char)bytes[begin]);}pos++;begin++;end++;for(;pos<bytes.length;pos++,end++){if(bytes[pos]=='\\r')break;}StringBuilder protocl=new StringBuilder();for(;begin<end;begin++){protocl.append((char)bytes[begin]);}Request request=new Request(method.toString(),url.toString(),protocl.toString(),socket);Response response=new Response(request);MyServlet myServlet=new MyServlet();myServlet.service(request,response);response.complete();} catch (IOException e) {e.printStackTrace();} catch (ServletException e) {e.printStackTrace();}}
}

ResponseServletOutputStream类

public class ResponseServletOutputStream extends ServletOutputStream {private byte[] bytes=new byte[1024];private int pos=0;public byte[] getBytes() {return bytes;}public int getPos() {return pos;}@Overridepublic void write(int b) throws IOException {}@Overridepublic void write(byte[] b) throws IOException {for (byte b1 : b) {bytes[pos]=b1;pos++;}}@Overridepublic boolean isReady() {return false;}@Overridepublic void setWriteListener(WriteListener writeListener) {}}

日常生活知识