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); } @Override public void addHeader(String s, String s1) { headers.put(s,s1); } @Override public void setStatus(int i, String s) { status=i; message=s; } @Override public int getStatus() { return status; } @Override public ResponseServletOutputStream getOutputStream() throws IOException { return responseServletOutputStream; } }
MyServlet类
public class MyServlet extends HttpServlet { @Override protected 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; } @Override public 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; } @Override public void write(int b) throws IOException { } @Override public void write(byte[] b) throws IOException { for (byte b1 : b) { bytes[pos]=b1; pos++; } } @Override public boolean isReady() { return false; } @Override public void setWriteListener(WriteListener writeListener) { } }