实现一个简陋的服务器(理解服务器的核心容器以及servlet工作原理)

    技术2024-11-06  8

    文章目录

    目的服务器实现步骤req和resp的定义MyServlet模板的定义==加载核心容器==服务器端多线程访问处理 目录结构

    目的

    理解服务器的核心容器以及servlet工作原理。

    服务器实现步骤

    浏览器发起的每个请求,都需要解析和响应,对请求报文解析,和响应报文部分内容封装请求对象和响应对象(HttpServletRequest和HttpServletResponse都是接口,由org.apache.catalina.connector(Tomcat)包下面的RequestFacade和ResponseFacade实现并进行实例化)。

    定义处理服务类的标准格式(MyServlet)

    加载核心容器(MyServlet容器),开启监听

    服务器端多线程处理

    ps:socket是对TCP/IP协议的封装。

    req和resp的定义

    遵循http协议,解析请求、响应报文。MyReq.java public class MyReq { private String method; private String url; public MyReq(InputStream is) { BufferedReader br = new BufferedReader(new InputStreamReader(is)); try { String reqHeader = br.readLine(); String[] reqHeaderArr = reqHeader.split(" "); this.method = reqHeaderArr[0]; this.url = reqHeaderArr[1]; } catch (IOException e) { e.printStackTrace(); } } public String getMethod() { return method; } public String getUrl() { return url; } } MyResp.java public class MyResp { public static String respHeader = "HTTP/1.1 200 OK\r\n" + "Content-Type:text/html;charset=utf-8\r\n" + "\r\n"; private OutputStream writer; public MyResp(OutputStream os) { this.writer = os; } public OutputStream getWriter() { return writer; } }

    MyServlet模板的定义

    MyServlet.java public abstract class MyServlet { public void doService(MyReq req, MyResp resp) { String reqMethod = req.getMethod(); if ("GET".equals(reqMethod)) { doGet(req, resp); } else { doPost(req, resp); } } public abstract void doGet(MyReq req, MyResp resp); public abstract void doPost(MyReq req, MyResp resp); } 编写两个类继承MyServlet模板,以作测试 public class LoginServlet extends MyServlet { @Override public void doGet(MyReq req, MyResp resp) { OutputStream respWriter = resp.getWriter(); try { respWriter.write(MyResp.respHeader.getBytes()); respWriter.write("login ok!".getBytes()); respWriter.flush(); respWriter.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void doPost(MyReq req, MyResp resp) { doGet(req, resp); } } public class RegistServlet extends MyServlet { @Override public void doGet(MyReq req, MyResp resp) { OutputStream respWriter = resp.getWriter(); try { respWriter.write(MyResp.respHeader.getBytes()); respWriter.write("register ok!".getBytes()); respWriter.flush(); respWriter.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void doPost(MyReq req, MyResp resp) { doGet(req, resp); } }

    加载核心容器

    配置文件:myMapping.properties servlet.one.url=/login servlet.one.class=com.myserver.servlet.LoginServlet servlet.two.url=/regist servlet.two.class=com.myserver.servlet.RegistServlet MyServer.java public class MyServer { static Map<String, MyServlet> myMapping = new HashMap<>();// 核心容器 static Properties prop = new Properties(); public static void myInit() { try { // 读取配置文件 prop.load(MyServer.class.getResourceAsStream("/myMapping.properties")); Set<Object> set = prop.keySet(); set.forEach(k -> { if (k.toString().contains("url")) { // 获得url的servlet的对应 String url = prop.getProperty(k.toString()); String classKey = k.toString().replace("url", "class"); String className = prop.getProperty(classKey); try { // 通过类名获得实例 MyServlet myms = (MyServlet) Class.forName(className).newInstance(); // 将url与myServlet的映射关系存入映射表中 myMapping.put(url, myms); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }); } catch (Exception e) { e.printStackTrace(); } } public static void serverBegin() { try { ServerSocket ss = new ServerSocket(8021); System.out.println("开始监听 8021 端口,等待访问..."); while (true) { // 同时满足多人访问,多线程 Socket accept = ss.accept(); Thread myThread = new Thread(new MyProccess(accept)); myThread.start(); } } catch (IOException e) { e.printStackTrace(); } } /** * 启动服务器 * @param args */ public static void main(String[] args) { MyServer.myInit(); MyServer.serverBegin(); } }

    服务器端多线程访问处理

    MyProccess.java public class MyProccess implements Runnable { private Socket accept; public MyProccess(Socket accept) { this.accept = accept; } @Override public void run() { try { // 服务器针对浏览器的每一次请求创建req和resp对象 MyReq req = new MyReq(accept.getInputStream()); MyResp resp = new MyResp(accept.getOutputStream()); // myMapping即为核心容器 MyServlet myServlet = MyServer.myMapping.get(req.getUrl()); if (myServlet != null) { myServlet.doService(req, resp); } else { OutputStream respWriter = resp.getWriter(); respWriter.write(MyResp.respHeader.getBytes()); respWriter.write("404 not found!".getBytes()); respWriter.flush(); respWriter.close(); } } catch (IOException e) { e.printStackTrace(); } } }

    目录结构

    Processed: 0.052, SQL: 9