手写一个民用Tomcat (08)

这次我们Tomcat 的改动是  指责分离,同时引入一个Wrapper封装

我们的Processor 是负责处理处理请求的任务

我们的Connector 是负责通信的 

详细代码如下

public class JxdHttpConnector implements Runnable {
    int minProcessors = 3;
    int maxProcessors = 10;
    int curProcessors = 0;
    //存放多个processor的池子
    Deque<JxdHttpProcessor> processorDeque = new ArrayDeque<>();
    private  ServletContainer container;

    //sessions map存放session
    public static Map<String, HttpSession> sessions = new ConcurrentHashMap<>();

    //创建新的session
    public static JxdSession createSession() {
        JxdSession session = new JxdSession();
        session.setValid(true);
        session.setCreationTime(System.currentTimeMillis());
        String sessionId = generateSessionId();
        session.setId(sessionId);
        sessions.put(sessionId, session);
        return (session);
    }

    /**
     * 生成随机数方法
     * @return
     */
    protected static synchronized String generateSessionId() {
        Random random = new Random();
        long seed = System.currentTimeMillis();
        random.setSeed(seed);
        byte bytes[] = new byte[16];
        random.nextBytes(bytes);
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
            byte b2 = (byte) (bytes[i] & 0x0f);
            if (b1 < 10)
                result.append((char) ('0' + b1));
            else
                result.append((char) ('A' + (b1 - 10)));
            if (b2 < 10)
                result.append((char) ('0' + b2));
            else
                result.append((char) ('A' + (b2 - 10)));
        }
        return (result.toString());
    }


    @Override
    public void run() {
        ServerSocket serverSocket = null;
        int port = 8080;
        try {
            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }

        //初始化池子 最开始三个
        initProcessorDeque();

        while (true) {
            Socket socket = null;
            try {
                //这是单线程 一个请求一个请求获取socket
                socket = serverSocket.accept();

                //得到一个新的processor,这个processor从池中获取(池中有可能新建)
                JxdHttpProcessor processor = createProcessor();
                if (processor == null) {
                    socket.close();
                    continue;
                }
                processor.assign(socket);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void start() {
        Thread thread = new Thread(this);
        thread.start();
    }

    //从池子中获取一个processor,如果池子为空且小于最大限制,则新建一个
    private JxdHttpProcessor createProcessor() {
        synchronized (processorDeque) {
            if (processorDeque.size() > 0) {
                return processorDeque.pop();
            }
            if (curProcessors < maxProcessors) {
                return newProcessor();
            } else {
                return null;
            }
        }
    }

    private void initProcessorDeque() {
        for (int i = 0; i < minProcessors; i++) {
            JxdHttpProcessor processor = new JxdHttpProcessor(this);
            processor.start();
            processorDeque.push(processor);
        }
        curProcessors = minProcessors;
    }


    private JxdHttpProcessor newProcessor() {
        JxdHttpProcessor jxdHttpProcessor = new JxdHttpProcessor(this);
        jxdHttpProcessor.start();
        processorDeque.push(jxdHttpProcessor);
        curProcessors++;
        return processorDeque.pop();
    }

    public void recycle(JxdHttpProcessor processor) {
        processorDeque.push(processor);
    }


    public ServletContainer getContainer() {
        return container;
    }

    public void setContainer(ServletContainer container) {
        this.container = container;
    }
}

public class JxdHttpProcessor implements Runnable {
    boolean available = false;
    Socket socket;

    JxdHttpConnector connector;
    private int serverPort = 0;
    private boolean keepAlive = false;
    private boolean http11 = true;
    public JxdHttpProcessor(JxdHttpConnector connector) {
        this.connector = connector;
    }

    private void process(Socket socket) { //服务器循环等待请求并处理
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        InputStream input = null;
        OutputStream output = null;

        // create Request object and parse
        JxdRequest request = new JxdRequest();
        try {
            output = socket.getOutputStream();
            keepAlive = true;
            //先关掉keepAlive 目前 为了方便测试
//            while (keepAlive) {
                request.parse(socket);
                // create Response object
                JxdResponse response = new JxdResponse(output);
                response.setRequest(request);
                request.setResponse(response);
                //handle session
                if (request.getSessionId() == null || request.getSessionId().equals("")) {
                    request.getSession(true);
                }
                response.setCharacterEncoding("UTF-8");
                response.addHeader(DefaultHeaders.CONTENT_TYPE_NAME, "text/html;charset=UTF-8");
                response.sendHeaders();//发送响应头
                //这段代码是测试用,可以获取的 请求参数 支持get 和post
                Map<String, String[]> map = request.getParameterMap();

                if (request.getUri().startsWith("/servlet/")) {
                    //加载动态资源
                    JxdServletProcessor jxdServletProcessor = new JxdServletProcessor(connector);
                    jxdServletProcessor.process(request, response);
                } else {
                    //加载静态资源
                    StaticResourceProcessor staticResourceProcessor = new StaticResourceProcessor();
                    staticResourceProcessor.process(request, response);
                }
                response.finishResponse();
                System.out.println("response header connection------"+response.getHeader("Connection"));
                if ("close".equals(response.getHeader("Connection"))) {
                    keepAlive = false;
                }
//            }
            //因为是多线程所以只能交给httpProcessor 来关闭
            socket.close();
        } catch (Exception ea) {
            ea.printStackTrace();
        }
    }


    @Override
    public void run() {
        while (true) {
            // 等待socket分配过来
            Socket socket = await();
            if (socket == null) continue;
            // 处理请求
            process(socket);
            // 回收processor
            connector.recycle(this);
        }
    }

    public void start() {
        Thread thread = new Thread(this);
        thread.start();
    }

    private synchronized Socket await() {
        // 等待connector提供一个新的socket
        while (!available) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 获得这个新的Socket
        Socket socket = this.socket;
        //设置标志为false
        available = false;
        //通知另外的线程
        notifyAll();
        return (socket);
    }

    public synchronized void assign(Socket socket) {
        // 等待connector提供一个新的socket
        while (available) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        // 获取到这个新的Socket
        this.socket = socket;
        // 把标志设置回去
        available = true;
        //通知另外的线程
        notifyAll();
    }
}

同时引入一个Wapper

/**
 * ServletContainer 主要用servletClsMap,servletInstanceMap 两个
 * map 管理Servlet
 */
public class ServletWrapper {
    private Servlet instance = null;
    private String servletClass;
    private ClassLoader loader;
    private String name;
    protected ServletContainer container = null;
    public ServletWrapper(String servletClass, ServletContainer container) {
        this.container = container;
        this.servletClass = servletClass;
        try {
            loadServlet();
        } catch (ServletException e) {
            e.printStackTrace();
        }
    }
    public ClassLoader getLoader() {
        if (loader != null)
            return loader;
        return container.getLoader();
    }

    public Servlet getServlet(){
        return this.instance;
    }
    public Servlet loadServlet() throws ServletException {
        if (instance!=null) return instance;

        Servlet servlet = null;
        String actualClass = servletClass;
        if (actualClass == null) {
            throw new ServletException("servlet class has not been specified");
        }
        ClassLoader classLoader = getLoader();
        Class classClass = null;
        try {
            if (classLoader!=null) {
                classClass = classLoader.loadClass(actualClass);
            }
        }
        catch (ClassNotFoundException e) {
            throw new ServletException("Servlet class not found");
        }
        try {
            servlet = (Servlet) classClass.newInstance();
        }
        catch (Throwable e) {
            throw new ServletException("Failed to instantiate servlet");
        }
        try {
            servlet.init(null);
        }
        catch (Throwable f) {
            throw new ServletException("Failed initialize servlet.");
        }
        instance =servlet;
        return servlet;
    }
    public void invoke(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        if (instance != null) {
            instance.service(request, response);
        }
    }
}

引入一个Servlet 容器 ,里边是一个map 用来管理 Servlet 不必每次都要创建

/**
 * ServletContainer 主要用servletClsMap,servletInstanceMap 两个
 * map 管理Servlet
 */
public class ServletContainer {
    JxdHttpConnector connector = null;
    ClassLoader loader = null;
    //包含servlet类和实例的map
    Map<String, String> servletClsMap = new ConcurrentHashMap<>(); //servletName -
    Map<String, ServletWrapper> servletInstanceMap = new ConcurrentHashMap<>();//servletN


    public ServletContainer() {
        try {
// create a URLClassLoader
            URL[] urls = new URL[1];
            URLStreamHandler streamHandler = null;
            File classPath = new File(JxdHttpServer.WEB_ROOT);
            String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
            urls[0] = new URL(null, repository, streamHandler);
            loader = new URLClassLoader(urls);
        } catch (IOException e) {
            System.out.println(e.toString());
        }
    }

    public String getInfo() {
        return null;
    }

    public ClassLoader getLoader() {
        return this.loader;
    }

    public void setLoader(ClassLoader loader) {
        this.loader = loader;
    }

    public JxdHttpConnector getConnector() {
        return connector;
    }

    public void setConnector(JxdHttpConnector connector) {
        this.connector = connector;
    }

    public String getName() {
        return null;
    }

    public void setName(String name) {
    }

    //invoke方法用于从map中找到相关的servlet,然后调用
    public void invoke(JxdRequest request, JxdResponse response) throws IOException, ServletException {
        ServletWrapper servletWrapper = null;
        String uri = request.getUri();
        //首先根据uri最后一个/号来定位,后面的字符串认为是servlet名字
        String servletName = uri.substring(uri.lastIndexOf("/") + 1);
        String servletClassName = servletName;
        servletWrapper = servletInstanceMap.get(servletName);
        //如果容器内没有这个servlet,先要load类,创建新实例
        if (servletWrapper == null) {
            servletWrapper = new ServletWrapper(servletClassName, this);
            this.servletClsMap.put(servletName, servletClassName);
            this.servletInstanceMap.put(servletName, servletWrapper);
        }
        try {
            HttpRequestFacade requestFacade = new HttpRequestFacade(request);
            HttpResponseFacade responseFacade = new HttpResponseFacade(response);
            System.out.println("Call service()");
            //让servletWrapper去执行servlet
            servletWrapper.invoke(requestFacade,responseFacade);
        } catch (Exception e) {
            System.out.println(e.toString());
        } catch (Throwable e) {
            System.out.println(e.toString());
        }
    }
}

JxdHttpServer 我们的启动类 也发发生了变化
public class JxdHttpServer {
    public static final String WEB_ROOT = System.getProperty("user.dir");

    public static final String FILE_ROOT = "D:\\";

    public static void main(String[] args) {
        JxdHttpConnector connector = new JxdHttpConnector();
        ServletContainer container = new ServletContainer();
        connector.setContainer(container);
        container.setConnector(connector);
        connector.start();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/580185.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

winrar压缩时排除指定目录排除所有子目录下的目录名称排除所有不需要的目录减小备份体积移除中间目录惊喜

winrar排除指定目录所有指定目录 说明(废话)解决方1. 打开 WinRAR。2. 导航到你要压缩的目录&#xff0c;然后选择该目录中的文件或文件夹。3. 点击“添加”按钮。4. 在弹出的“压缩文件名和参数”窗口中&#xff0c;切换到“文件”标签页。5. 在“文件”标签页中&#xff0c;找…

Topaz Gigapixel AI v7.1.2激活版:智能图像增强与放大

Topaz Gigapixel AI&#xff0c;这款基于人工智能技术的图像处理软件&#xff0c;以其卓越的功能和高效的性能&#xff0c;为图像处理领域注入了新的活力。 Topaz Gigapixel AI v7.1.2激活版下载 作为一款专注于图像增强与放大的软件&#xff0c;Topaz Gigapixel AI利用深度学习…

数据结构11:二叉树的链式结构

文章目录 快速创建链式二叉树二叉树的遍历前序、中序、后序层序 二叉树的基本操作二叉树的节点个数二叉树叶节点的个数二叉树第k层结点个数二叉树查找值为x的结点 二叉树基础oj练习单值二叉树检查两颗树是否相同对称二叉树二叉树的前序遍历另一颗树的子树 二叉树的创建和销毁二…

哈密顿函数和正则方程

9-2 哈密顿函数和正则方程_哔哩哔哩_bilibili 拉格朗日函数是广义坐标和广义速度的函数 哈密顿函数是广义坐标和广义动量的函数 拉格朗日函数经过勒让德变换得到哈密顿函数

设计普遍逼近的深度神经网络:一阶优化方法

论文地址&#xff1a;https://ieeexplore.ieee.org/document/10477580 传统的基于优化的神经网络设计方法通常从一个具有显式表示的目标函数出发&#xff0c;采用特定的优化算法进行求解&#xff0c;再将优化迭代格式映射为神经网络架构&#xff0c;例如著名的 LISTA-NN 就是利…

无人零售与传统便利店的竞争优势

无人零售与传统便利店的竞争优势 成本控制 • 无人零售 显著降低了人力成本&#xff0c;无需支付店员薪资和相关福利&#xff0c;且通过智能化管理减少能源消耗与维护费用&#xff0c;尤其在高租金和高人流区域效益突出。 • 传统便利店 则承担较高的人员开支&#xff0c;…

linux安装maven

linux安装maven 先安装java环境&#xff0c;比如笔者自己的这个 http://t.csdnimg.cn/mNpFO 现在版本已经来到了3.9.6 1、下载这个maven的link链接 2、创建文件夹 mkdir -p /usr/local/maven #为了可以上传成功(也可以不用。) chmod -R 777 /usr/local/maven #这个可以使用…

【深入理解神经网络:预测和评估】

文章目录 前言环境准备数据导入和处理数据归一化神经网络的创建与训练预测与评估结果可视化应用结论 前言 在这篇博客文章中&#xff0c;我们将深入研究利用神经网络进行数据预测和性能评估的过程。我们将详解在MATLAB环境下使用的一个例子&#xff0c;该例子展示了如何使用MAT…

学pyhton的第二十二天

原文链接&#xff1a;Python 图形化界面设计&#xff08;Tkinter&#xff09; - 简书 (jianshu.com) 相关博客链接 接第十八天Tkinter的内容&#xff1a; 单选按钮&#xff08;控件&#xff1a;Radiobutton&#xff09;&#xff1a; 除共有属性外&#xff0c;还具有显示文本…

uniapp对uni.request()的封装以及使用

官方文档 uni.request(OBJECT) | uni-app官网 (dcloud.net.cn) uni.request参数 参数名说明url是写api地址的data是用来传值的对于 GET 方法&#xff0c;会将数据 转换为 query string。例如 { name: name, age: 18 } 转换后的结果是 namename&age18。对于 POST 方法且 …

BUUCTF:Basic 解析(一)

一、Linux Labs 打开靶场 F12 源代码啥也没有&#xff0c;但是题目给出了 ssh 连接的用户名密码端口号及主机&#xff0c;推测应该是要连接&#xff0c;打开 XShell 连接 设置用户名及密码 连接成功&#xff0c;随后找到 flag 二、BUU LFI COURSE 1 打开靶场 F12 检查源代码…

微火快报:全域外卖服务商是什么?如何成为全域外卖服务商?

最近&#xff0c;互联网行业又出现了一个新名词——全域外卖服务商&#xff0c;很多人都预感到它可能是下一个风口&#xff0c;却因为不了解概念和找不到入局的途径而止步不前。那么本期&#xff0c;我们就来重点讲一讲全域外卖服务商的概念、发展前景以及入局的途径。 所谓的全…

电脑进水不用怕,教你几招恢复如初!

电脑进水是一种常见但严重的问题&#xff0c;可能会导致电脑损坏&#xff0c;甚至无法正常使用。在遇到电脑进水的情况下&#xff0c;正确的处理方式至关重要&#xff0c;可以最大程度地减少损害并提高修复成功的可能性。本文将介绍三种解决电脑进水问题的方法&#xff0c;帮助…

flutter笔记-主要控件及布局

文章目录 1. 富文本实例2. Image2.1 本地图片2.2 网络图片 笔记3. 布局4. 滑动相关view4.1 GridView类似九宫格view4.2 ListView 关于widget的生命周期的相关知识这里就不做介绍&#xff0c;和很多语言类似&#xff1b; 1. 富文本实例 Dart中使用richtext&#xff0c;示例如下…

怎么通过PHP语言实现远程控制棋牌室

怎么通过PHP语言实现远程控制棋牌室呢&#xff1f; 本文描述了使用PHP语言调用HTTP接口&#xff0c;实现控制棋牌室&#xff0c;通过专用的包间控制器&#xff0c;来实现包间内所有电器以及门锁的独立控制。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规…

deepin-IDE, 体验AI编程,拿精美定制礼品!

内容来源&#xff1a;deepin&#xff08;深度&#xff09;社区 UOS AI 已经上线半年了&#xff0c;想必很多小伙伴在这半年里都体会到了人工智能的魅力。 那你们知道&#xff0c;在 deepin-IDE 中&#xff0c;可以用 AI 写代码吗&#xff1f;deepin-IDE 结合强大的 AI 编辑代码…

合合信息Embedding模型获得MTEB中文榜单第一

前言 最近几年&#xff0c;可以说大语言模型汇聚了所有的光彩&#xff0c;大语言模型的飞速发展更是吸引着社会各界的目光&#xff0c;这些模型的强大能力源自于Embedding技术的支撑&#xff0c;这种技术将语言转化为机器可理解的数值向量。随着大型语言模型的不断突破&#x…

ssh 文件传输:你应该掌握的几种命令行工具

这篇文章主要分享一下我使用过的 ssh 传输文件的进阶路程&#xff0c;从 scp -> lrzsz -> trzsz&#xff0c;希望能给你带来一些帮助&#xff5e; scp scp 命令可以用于在 linux 系统之间复制文件&#xff0c;具体的语法可以参考下图 其实使用起来也还比较方便&#x…

java-注解

简介 自定义注解 定义 // 自定义注解 public interface MyAnnotation {// 注解的属性// value是注解的一个属性&#xff0c;如果只有一个属性&#xff0c;建议使用valueString value() default "";boolean enabled() default true;String[] exclude() default {}; }使…

适用于Windows和Mac的十大误删除数据恢复软件

数据恢复是从辅助存储或可移动文件中找回丢失、删除或损坏的数据的过程。数据丢失的原因有很多。因此&#xff0c;有必要恢复已删除的数据。有各种可用的软件工具&#xff0c;使用户能够恢复任何类型的已删除数据。但是&#xff0c;任何数据恢复都有四个主要阶段。他们正在修复…
最新文章