`
芝加哥09
  • 浏览: 59171 次
社区版块
存档分类
最新评论

自己动手写Tomcat

阅读更多

最近研究一方socket编程,由于想动手写关于socket方面的东西。然而我们知道通过URL去访问某网址,其实其底层用的就是socket,于是我就写了一个很简单的tomcat服务器,主要目地在于学习,在此分享给大家。同时提供下载源工程。

 

我写的工程用Maven管理的,但是我没有引入其它的JAR包,为此我就不列出pom.xml文件了。

在此简要地说明每个类的作用:

 

Server.java

该类的作用就是将服务提起来的,并且利用线程池。

 

package com.cloud.tomcat.server;

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
    private static ServerSocket serverSocket;
    private static ExecutorService executorService;
    private final static int POOL_SIZE = 15;

    public static void main(String[] args) throws Exception {
        serverSocket = new ServerSocket(8080);
        Socket socket = null;
        executorService = Executors.newFixedThreadPool(POOL_SIZE);

        while (true) {
            socket = serverSocket.accept();
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
            writer.println("HTTP/1.1 200 OK");
            writer.println("Content-Type: text/html;charset=UTF-8");
            writer.println();

            executorService.execute(new Handler(socket, writer));
        }
    }
}

 

 

Handler.java

该类的作用是根据浏览器传过来信息做出相应的处理,同时实现Runnable接口。

 

package com.cloud.tomcat.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import com.cloud.tomcat.servlet.HttpServlet;

public class Handler implements Runnable {
    private Socket socket;
    private PrintWriter writer;

    public Handler(Socket socket, PrintWriter writer) {
        this.socket = socket;
        this.writer = writer;
    }

    @Override
    public void run() {
        try {
            InputStream inputStream = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String path = "";
            String method = "";

            while (true) {
                String msg = reader.readLine();
                if (null == msg || "".equals(msg.trim())) {
                    break;
                }

                String[] msgs = msg.split(" ");
                if (3 == msgs.length && "HTTP/1.1".equalsIgnoreCase(msgs[2])) {
                    method = msgs[0];
                    path = msgs[1];
                    break;
                }
            }

            if (path.endsWith("ico")) {
                return;
            }

            HttpServlet httpServlet = ServletContainer.getHttpServlet(path);
            String html = "";
            if ("GET".equals(method)) {
                html = httpServlet.doGet();
            } else if ("POST".equals(method)) {
                html = httpServlet.doGet();
            }
            writer.write(html);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                writer.close();
                socket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
    }

}

 

 

ServletContainer.java

该类首先会解析web.xml文件,然后根据url的信息,拿到相应的servlet。

 

package com.cloud.tomcat.server;

import java.util.HashMap;
import java.util.Map;

import com.cloud.tomcat.model.Servlet;
import com.cloud.tomcat.model.ServletMapping;
import com.cloud.tomcat.servlet.HttpServlet;
import com.cloud.tomcat.util.XMLUtil;

public class ServletContainer {
    private static Map<String, Object> servletMaps = new HashMap<String, Object>();
    private static Map<String, Object> servletMappingMaps = new HashMap<String, Object>();
    private static Map<String, HttpServlet> servletContainer = new HashMap<String, HttpServlet>();

    static {
        try {
            Map<Integer, Map<String, Object>> maps = XMLUtil.parseWebXML();
            if (null != maps && 2 == maps.size()) {
                servletMaps = maps.get(0);
                servletMappingMaps = maps.get(1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static HttpServlet getHttpServlet(String path) {

        if (null == path || "".equals(path.trim()) || "/".equals(path)) {
            path = "/index";
        }
    
        if (servletContainer.containsKey(path)) {
            return servletContainer.get(path);
        }

        if (!servletMappingMaps.containsKey(path)) {
            return null;
        }
        ServletMapping servletMapping = (ServletMapping) servletMappingMaps.get(path);
        String name = servletMapping.getName();

        if (!servletMaps.containsKey(name)) {
            return null;
        }
        Servlet servlet = (Servlet) servletMaps.get(name);
        String clazz = servlet.getClazz();

        if (null == clazz || "".equals(clazz.trim())) {
            return null;
        }

        HttpServlet httpServlet = null;
        try {
            httpServlet = (HttpServlet) Class.forName(clazz).newInstance();
            servletContainer.put(path, httpServlet);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return httpServlet;
    }
}

 

 

HttpServlet.java

为了实现起来简单方便,我自己定义了一个HttpServlet。

 

package com.cloud.tomcat.servlet;

public interface HttpServlet {
    public String doGet();
    public String doPost();
}

 

 

CloudServlet.java

HttpServlet的具体实现类。

 

package com.cloud.tomcat.servlet;

public class CloudServlet implements HttpServlet {

    @Override
    public String doGet() {
        return this.doPost();
    }

    @Override
    public String doPost() {
        return "<h1>Chicago at Cloud!!!</h1>";
    }

}

 

 

下面一一列出解析web.xml用到的类,由于我没有引入第三JAR包,可能这部分有点麻烦。

Servlet.java

 

package com.cloud.tomcat.model;

public class Servlet {
    private String name;
    private String clazz;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }
}

 

ServletMapping.java

 

package com.cloud.tomcat.model;

public class ServletMapping {
    private String name;
    private String url;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

 

XMLUtil.java

package com.cloud.tomcat.util;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.cloud.tomcat.model.Servlet;
import com.cloud.tomcat.model.ServletMapping;

public class XMLUtil {

    public static Map<Integer, Map<String, Object>> parseWebXML() throws Exception {
        Map<Integer, Map<String, Object>> result = new HashMap<Integer, Map<String,Object>>();
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();

        InputStream in = XMLUtil.class.getClassLoader().getResourceAsStream("web.xml");
        Document document = db.parse(in);
        Element root = document.getDocumentElement();
        NodeList xmlNodes = root.getChildNodes();
        for (int i = 0; i < xmlNodes.getLength(); i++) {
            Node config = xmlNodes.item(i);
            if (null != config && config.getNodeType() == Node.ELEMENT_NODE) {
                String nodeName1 = config.getNodeName();
                if ("servlet".equals(nodeName1)) {
                    Map<String, Object> servletMaps = null;
                    if (result.containsKey(0)) {
                        servletMaps = result.get(0);
                    } else {
                        servletMaps = new HashMap<String, Object>();
                    }

                    NodeList childNodes = config.getChildNodes();
                    Servlet servlet = new Servlet();
                    for (int j = 0; j < childNodes.getLength(); j++) {
                        Node node = childNodes.item(j);
                        if (null != node && node.getNodeType() == Node.ELEMENT_NODE) {
                            String nodeName2 = node.getNodeName();
                            String textContent = node.getTextContent();
                            if ("servlet-name".equals(nodeName2)) {
                                servlet.setName(textContent);
                            } else if ("servlet-class".equals(nodeName2)) {
                                servlet.setClazz(textContent);
                            }
                        }
                    }
                    servletMaps.put(servlet.getName(), servlet);

                    result.put(0, servletMaps);
                } else if ("servlet-mapping".equals(nodeName1)) {
                    Map<String, Object> servletMappingMaps = null;
                    if (result.containsKey(1)) {
                        servletMappingMaps = result.get(1);
                    } else {
                        servletMappingMaps = new HashMap<String, Object>();
                    }

                    NodeList childNodes = config.getChildNodes();
                    ServletMapping servletMapping = new ServletMapping();
                    for (int j = 0; j < childNodes.getLength(); j++) {
                        Node node = childNodes.item(j);
                        if (null != node && node.getNodeType() == Node.ELEMENT_NODE) {
                            String nodeName2 = node.getNodeName();
                            String textContent = node.getTextContent();
                            if ("servlet-name".equals(nodeName2)) {
                                servletMapping.setName(textContent);
                            } else if ("url-pattern".equals(nodeName2)) {
                                servletMapping.setUrl(textContent);
                            }
                        }
                    }
                    servletMappingMaps.put(servletMapping.getUrl(), servletMapping);

                    result.put(1, servletMappingMaps);
                }
            }
        }
        return result;
    }

    public static void main(String[] args) throws Exception {
        System.out.println(parseWebXML());
    }
}

 

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5"> 

    <servlet>
        <servlet-name>cloud</servlet-name>
        <servlet-class>com.cloud.tomcat.servlet.CloudServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>cloud</servlet-name>
        <url-pattern>/index</url-pattern>
    </servlet-mapping>
</web-app>

 

运行结果:

将Server类运行起来,然后用浏览器输入:

http://localhost:8080/index或http://localhost:8080

得到如下结果:


 



 

 

  • 大小: 8.7 KB
  • 大小: 8.2 KB
13
12
分享到:
评论
25 楼 zhengzhigang2016 2017-01-02  
谢谢分享啊
24 楼 lvwenwen 2014-03-13  
mark,不错,学习了。。。
23 楼 liang8768 2014-03-02  
mark,有时间向楼主学习一下。。。。
22 楼 mengfei86 2014-03-01  
挺好,学习了
21 楼 芝加哥09 2014-02-28  
commx 写道
仿佛在看nodejs的入门教学一般
感谢作者分享

。。。我们一起加油。。。
20 楼 芝加哥09 2014-02-28  
ahack 写道
每当我想写或者写了一个东西的时候都能在iteye或者其他地方看到有人做同样的事情。难道是传说中的猿粪。

呵呵。。。这就是我们程序员的共性吧。。。
19 楼 芝加哥09 2014-02-28  
douyouguo 写道
学习了,很简单很好!

。。。一起加油。。。
18 楼 芝加哥09 2014-02-28  
string2020 写道
能不能解析jsp

我这个例子主要体现socket,还不能解析jsp。
17 楼 芝加哥09 2014-02-28  
jimmee 写道
建议多看已有的开源代码, 适当动手.

嗯。。。看开源代码,对自己的确有很大的帮助。。。
16 楼 芝加哥09 2014-02-28  
weijs 写道
慢慢学习,谢谢分享

嗯。。。共同进步。。。
15 楼 芝加哥09 2014-02-28  
jilo88 写道
写的非常好,一看就清析了,对tomcat的执行原理和结构就有了大体流程上的认识。 

谢谢。。。我这里主要体现socket,有很多细节也没有考虑到。。。
14 楼 芝加哥09 2014-02-28  
m635674608 写道
书上的demo啊。、

。。。能告诉我是哪本书吗,我想去看看。。。谢谢哦。。。
13 楼 芝加哥09 2014-02-28  
robert.wei 写道
思路是清晰的。 其实一个服务器本身也没有太多的东西。
看看mina就知道

嗯。。。不过,我还是没有考虑很多细节。。。主要是为了体现socket编程。。。
12 楼 芝加哥09 2014-02-28  
bewithme 写道
值得表扬,让人比较容易理解的。

谢谢。。。动手才有利于知识的掌握。。。
11 楼 commx 2014-02-28  
仿佛在看nodejs的入门教学一般
感谢作者分享
10 楼 ahack 2014-02-28  
每当我想写或者写了一个东西的时候都能在iteye或者其他地方看到有人做同样的事情。难道是传说中的猿粪。
9 楼 douyouguo 2014-02-28  
学习了,很简单很好!
8 楼 dagmom 2014-02-28  
string2020 写道
能不能解析jsp
当然不能,缺少jsp编译工具,tomcat实现了很多功能的,不是简单的invoke servert method,包括session的管理,组件的扩展
7 楼 string2020 2014-02-28  
能不能解析jsp
6 楼 jimmee 2014-02-28  
建议多看已有的开源代码, 适当动手.

相关推荐

    自己动手写搜索引擎光盘源码 第一章

    上传不易,需要一个资源分是希望你能给个好评,这是自己动手写搜索引擎光盘的源码第一章,其中删除了tomcat客户端程序,以便于网速较慢的人快速下载。本源码对于想入门搜索引擎技术的人是很有帮助的!

    apche_tomcat负载均衡

    自己动手操作后,配置成功了。 写成文档,分享给大家。 另需要自己下载 tomcat 和apche

    tomcat7.0.88

    apache-tomcat-7.0.88-x64,解压后安装好服务即可使用,不是安装版,自己动手配置。解压即安装,极其简单易用,很好的学习工具

    apache-tomcat-7.0.64.zip

    tomcat7.0.64-windows-x64位,这个是稳定版本,zip包自己解压,不是安装版,自己动手配置。解压即安装,极其简单易用,很好的学习工具

    实例Apache负载均衡+Tomcat集群

    实例介绍Apache负载均衡与Tomcat集群的攻略,有兴趣的同学可以下载下来自己动手尝试一下哦!

    自己的手机或者AndroidStudio的虚拟机怎么连上电脑端的Tomcat服务器

    那如果我们想在客户端连接到自己电脑上的Tomcat服务器并显示这样的界面,应该怎么做呢? 不管是自己的手机还是AS里面的虚拟设备,我们首先都要知道自己PC的IP地址。 Win+R输入cmd打开windows命令行,输入ipconfig,...

    tomcat的配置使用详细版(小结)

    开发者开发部署web应用时通常使用tomcat服务器,很多初学者只懂得在开发工具上配置,但离开了开发工具,自己手动配置部署,并让一个项目跑起来,你会了吗。小编也遇到过这样的困扰。网上查找的资料说法不一,小编就...

    Eclipse_+_tomcat配置

    Eclipse_+_tomcat配置 内容很实在,经亲自动手测试过!实用

    tomcat配置的详细文档

    开发者开发部署web应用时通常使用tomcat服务器,很多初学者只懂得在开发工具上配置,但离开了开发工具,自己手动配置部署,并让一个项目跑起来,你会了吗。小编也遇到过这样的困扰。网上查找的资料说法不一,小编就...

    Nginx+Tomcat负载平衡,Redis管理session存储

    nginx 作为目前最流行的开源反向代理...博客已经很详细得说明方案及其代码,如果程序员没有很强的动手能力,那就要付出点代价来下载完整的环境方案。 该方案里面包含已经搭配好的nginx+tomcat+redies 欢迎讨论

    2、tomcat服务器搭建,超简单教程呦!快跟小编一起动手实践吧!!!「Java Web开发」

    Tomcat简单的说就是一个运行Java程序的网络服务器,tomcat服务器目前隶属于Apache 软件基金会。tomcat最初是由詹姆斯·邓肯·戴维森创建的,之后进行了开源化。目前tomcat的最新版本为9.0。 2、tomcat运行在哪里? ...

    JavaWeb婚庆商品、服务销售系统前后端+MVC三层架构+Mysql+Tomcat+可以用于毕设、课设学习

    JavaWeb婚庆商品、服务...达到了毕业设计的要求,同时锻炼了自己的动手能力。 具体可以查看演示视频:https://live.csdn.net/v/216138 查看博客链接:https://blog.csdn.net/qq_29009981/article/details/125266086

    Windows下使用Nginx+Tomcat做负载均衡的完整步骤

    今天,王子与大家闲谈一下如何在Windows下使用Nginx+Tomcat做负载均衡的完整步骤,小伙伴们可以试着自己动手实践一下哦。 另外说明一点,本篇文章是纯实操文章,不涉及太多原理的解读,后期可能单独开一个专栏来深入...

    基于ssm的婚恋系统源码.zip

    非常完整的项目源码,加注释说明,新手也可自己动手。框架整体采用SSM,java语言开发,可做为毕业设计和期末大作业。想拿高分的看过来 程序可正常启动,以下为环境说明: 开发语言:Java 框架:ssm JDK版本:JDK1.8...

    【JSP+Servlet+Tomcat】WEB项目初启动的那些糟心事

    文章目录配置好Tomcat操作流程我配置的index.jsp我配置的web.xmlJavaEE相关包的导入启动遇到...希望大家能认真地动手操作。 我配置的index.jsp 文件就是web文件夹下的index.jsp,后续我们看的也是这个文件: Servle

    svn web admin subversion的web管理工具管理服务器端的配置

    网上没有找到我们项目合适的svn web配置工具,于是自己动手,用jsp写了一个web版的管理工具svn web admin,subversion web 管理工具,发布到tomcat上直接可以修改服务器的配置文件,密码都加密保存,成员也可以自己...

    Java Web版SVN 远程配置管理工具

    网上没有找到合适的svn web配置工具,于是自己动手,用jsp写了一个web版的管理工具,发布到tomcat上直接可以修改配置文件,管理方便,工作效率大大提高。 附简单操作说明: 1、部署:将下载的压缩包直接解压到...

    毕业设计基于springboot的结合疫情情况的婚恋系统源码(也可作为期末大作业).zip

    非常完整的项目源码,加注释说明,新手也可自己动手。框架整体采用springboot,java语言开发,可做为毕业设计和期末大作业。想拿高分的看过来! 项目可正常启动,以下为开发所需环境: 开发语言:Java 框架:...

    server project

    自己动手写的简单Web服务器(附源码)!供参考

Global site tag (gtag.js) - Google Analytics