简单的实现一个Web容器
前提
- Socket
- IO
思路
- 启动 Socket 服务,循环接收浏览器请求
- 接收到请求之后,将流中的数据取出
- 判断目标资源是否存在,若不存在,返回 404
- 若存在,将目标资源通过输出流响应给客户端
代码
-
Tomcat
package com.apesblog.tomcat; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /** * @author ZhangYuShun * @since 2022/8/31 */ public class Tomcat { /** * 一个简单的Web容器 */ public static void main(String[] args) throws IOException { //定义ServerSocket8080端口 ServerSocket serverSocket = new ServerSocket(8080); //循环接受请求 while (true) { Socket socket = serverSocket.accept(); System.out.println(socket); new Thread(() -> { try { InputStream inputStream = socket.getInputStream(); Request request = new Request(inputStream); //创建Response OutputStream outputStream = socket.getOutputStream(); Response response = new Response(outputStream); //进行响应 response.sendRedirect(request.getUrl()); } catch (Exception e) { e.printStackTrace(); } }).start(); } } }
-
Request
package com.apesblog.tomcat; import java.io.IOException; import java.io.InputStream; /** * @author ZhangYuShun * @since 2022/8/31 */ public class Request { private String url; private String Method; public Request(InputStream inputStream) throws IOException { /** * 要一次读取多个字节时,经常用到InputStream.available()方法,这个方法可以在读写操作前先得知数据流里有多少个字节可以读取。需要注意的是,如果这个方法用在从本 * 地文件读取数据时,一般不会遇到问题,但如果是用于网络操作,就经常会遇到一些麻烦。 * 比如,Socket通讯时,对方明明发来了1000个字节,但是自己的程序调用available()方法却只得到900,或者100,甚至是0,感觉有点莫名其妙,怎么也找不到原因。 * 其实,这是因为网络通讯往往是间断性的,一串字节往往分几批进行发送。本地程序调用available()方法有时得到0, * 这可能是对方还没有响应,也可能是对方已经响应了,但是数据还没有送达本地。对方发送了1000个字节给你,也许分成3批到达, * 这你就要调用3次available()方法才能将数据总数全部得到。 */ int count = 0; while (count == 0) { count = inputStream.available(); } byte[] bytes = new byte[count]; inputStream.read(bytes); String content = new String(bytes); System.out.println(content); if ("".equals(content)) { System.out.println("空请求"); } else { //正则\s 转义\ String firstLine = content.split("\\n")[0]; this.setMethod(firstLine.split("\\s")[0]); this.setUrl(firstLine.split("\\s")[1]); } } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getMethod() { return Method; } public void setMethod(String method) { Method = method; } }
-
Response
package com.apesblog.tomcat; import java.io.BufferedInputStream; import java.io.File; import java.io.OutputStream; import java.nio.file.Files; public class Response { private OutputStream outputStream; public Response(OutputStream outputStream) { this.outputStream = outputStream; } public void sendRedirect(String uri) { //判断uri是否存在 //不存在返回404 //存在直接返回目标资源数据 File file = new File(Response.class.getResource("/").getPath() + uri); if (file.exists()) { try { //返回目标资源数据 BufferedInputStream bufferedInputStream = new BufferedInputStream(Files.newInputStream(file.toPath())); //存储每次读取的数据 byte[] bytes = new byte[1024]; //记录每次读取的有效字节个数 int len = 0; //TODO 感觉写的不好 字节转字符再转字节输出 不够优雅 StringBuilder result = new StringBuilder(); while ((len = bufferedInputStream.read(bytes)) != -1) { result.append(new String(bytes, 0, len)); } String response = getResponseMessage("200", result.toString()); System.out.println(response); this.outputStream.write(response.getBytes()); } catch (Exception e) { e.printStackTrace(); } } else { try { //返回404 String error = getResponseMessage("404", "404 File Not Found!"); this.outputStream.write(error.getBytes()); } catch (Exception e) { e.printStackTrace(); } } } public String getResponseMessage(String code, String message) { return "HTTP/1.1 " + code + "\r\n" + "Content-type: text/html\r\n" + "Content-Length: " + message.length() + "\r\n" + "\r\n" + message; } }
评论区