自己动手写Tomcat

今天看到有人写了个简单的tomcat,让我想起多年以前自己也写了个demo,兴奋了好意振。贴出来分享下。有些简陋...   自定义服务器及浏览器.rar


转:

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

 

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

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

 

Server.java

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

01. package com.cloud.tomcat.server;
02.  
03. import java.io.OutputStreamWriter;
04. import java.io.PrintWriter;
05. import java.net.ServerSocket;
06. import java.net.Socket;
07. import java.util.concurrent.ExecutorService;
08. import java.util.concurrent.Executors;
09.  
10. public class Server {
11. private static ServerSocket serverSocket;
12. private static ExecutorService executorService;
13. private final static int POOL_SIZE = 15;
14.  
15. public static void main(String[] args) throws Exception {
16. serverSocket = new ServerSocket(8080);
17. Socket socket = null;
18. executorService = Executors.newFixedThreadPool(POOL_SIZE);
19.  
20. while (true) {
21. socket = serverSocket.accept();
22. PrintWriter writer = new PrintWriter(newOutputStreamWriter(socket.getOutputStream(), "UTF-8"));
23. writer.println("HTTP/1.1 200 OK");
24. writer.println("Content-Type: text/html;charset=UTF-8");
25. writer.println();
26.  
27. executorService.execute(new Handler(socket, writer));
28. }
29. }
30. }


Handler.java

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

01. package com.cloud.tomcat.server;
02.  
03. import java.io.BufferedReader;
04. import java.io.IOException;
05. import java.io.InputStream;
06. import java.io.InputStreamReader;
07. import java.io.PrintWriter;
08. import java.net.Socket;
09.  
10. import com.cloud.tomcat.servlet.HttpServlet;
11.  
12. public class Handler implements Runnable {
13. private Socket socket;
14. private PrintWriter writer;
15.  
16. public Handler(Socket socket, PrintWriter writer) {
17. this.socket = socket;
18. this.writer = writer;
19. }
20.  
21. @Override
22. public void run() {
23. try {
24. InputStream inputStream = socket.getInputStream();
25. BufferedReader reader = new BufferedReader(newInputStreamReader(inputStream));
26. String path = "";
27. String method = "";
28.  
29. while (true) {
30. String msg = reader.readLine();
31. if (null == msg || "".equals(msg.trim())) {
32. break;
33. }
34.  
35. String[] msgs = msg.split(" ");
36. if (3 == msgs.length && "HTTP/1.1".equalsIgnoreCase(msgs[2])) {
37. method = msgs[0];
38. path = msgs[1];
39. break;
40. }
41. }
42.  
43. if (path.endsWith("ico")) {
44. return;
45. }
46.  
47. HttpServlet httpServlet = ServletContainer.getHttpServlet(path);
48. String html = "";
49. if ("GET".equals(method)) {
50. html = httpServlet.doGet();
51. else if ("POST".equals(method)) {
52. html = httpServlet.doGet();
53. }
54. writer.write(html);
55. writer.flush();
56. catch (IOException e) {
57. e.printStackTrace();
58. finally {
59. try {
60. writer.close();
61. socket.close();
62. catch (Exception e) {
63. e.printStackTrace();
64. }
65. }
66.  
67. }
68.  
69. }

ServletContainer.java


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


01. package com.cloud.tomcat.server;
02.  
03. import java.util.HashMap;
04. import java.util.Map;
05.  
06. import com.cloud.tomcat.model.Servlet;
07. import com.cloud.tomcat.model.ServletMapping;
08. import com.cloud.tomcat.servlet.HttpServlet;
09. import com.cloud.tomcat.util.XMLUtil;
10.  
11. public class ServletContainer {
12. private static Map<String, Object> servletMaps = new HashMap<String, Object>();
13. private static Map<String, Object> servletMappingMaps = new HashMap<String, Object>();
14. private static Map<String, HttpServlet> servletContainer = new HashMap<String, HttpServlet>();
15.  
16. static {
17. try {
18. Map<Integer, Map<String, Object>> maps = XMLUtil.parseWebXML();
19. if (null != maps && 2 == maps.size()) {
20. servletMaps = maps.get(0);
21. servletMappingMaps = maps.get(1);
22. }
23. catch (Exception e) {
24. e.printStackTrace();
25. }
26. }
27.  
28. public static HttpServlet getHttpServlet(String path) {
29.  
30. if (null == path || "".equals(path.trim()) || "/".equals(path)) {
31. path = "/index";
32. }
33.  
34. if (servletContainer.containsKey(path)) {
35. return servletContainer.get(path);
36. }
37.  
38. if (!servletMappingMaps.containsKey(path)) {
39. return null;
40. }
41. ServletMapping servletMapping = (ServletMapping) servletMappingMaps.get(path);
42. String name = servletMapping.getName();
43.  
44. if (!servletMaps.containsKey(name)) {
45. return null;
46. }
47. Servlet servlet = (Servlet) servletMaps.get(name);
48. String clazz = servlet.getClazz();
49.  
50. if (null == clazz || "".equals(clazz.trim())) {
51. return null;
52. }
53.  
54. HttpServlet httpServlet = null;
55. try {
56. httpServlet = (HttpServlet) Class.forName(clazz).newInstance();
57. servletContainer.put(path, httpServlet);
58. catch (Exception e) {
59. e.printStackTrace();
60. }
61. return httpServlet;
62. }
63. }


HttpServlet.java

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


1. package com.cloud.tomcat.servlet;
2.  
3. public interface HttpServlet {
4. public String doGet();
5. public String doPost();
6. }


CloudServlet.java

HttpServlet的具体实现类。


01. package com.cloud.tomcat.servlet;
02.  
03. public class CloudServlet implements HttpServlet {
04.  
05. @Override
06. public String doGet() {
07. return this.doPost();
08. }
09.  
10. @Override
11. public String doPost() {
12. return "<h1>Chicago at Cloud!!!</h1>";
13. }
14.  
15. }


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

Servlet.java


01. package com.cloud.tomcat.model;
02.  
03. public class Servlet {
04. private String name;
05. private String clazz;
06.  
07. public String getName() {
08. return name;
09. }
10.  
11. public void setName(String name) {
12. this.name = name;
13. }
14.  
15. public String getClazz() {
16. return clazz;
17. }
18.  
19. public void setClazz(String clazz) {
20. this.clazz = clazz;
21. }
22. }

ServletMapping.java


01. package com.cloud.tomcat.model;
02.  
03. public class ServletMapping {
04. private String name;
05. private String url;
06.  
07. public String getName() {
08. return name;
09. }
10.  
11. public void setName(String name) {
12. this.name = name;
13. }
14.  
15. public String getUrl() {
16. return url;
17. }
18.  
19. public void setUrl(String url) {
20. this.url = url;
21. }
22. }
XMLUtil.java



01. package com.cloud.tomcat.util;
02.  
03. import java.io.InputStream;
04. import java.util.HashMap;
05. import java.util.Map;
06.  
07. import javax.xml.parsers.DocumentBuilder;
08. import javax.xml.parsers.DocumentBuilderFactory;
09.  
10. import org.w3c.dom.Document;
11. import org.w3c.dom.Element;
12. import org.w3c.dom.Node;
13. import org.w3c.dom.NodeList;
14.  
15. import com.cloud.tomcat.model.Servlet;
16. import com.cloud.tomcat.model.ServletMapping;
17.  
18. public class XMLUtil {
19.  
20. public static Map<Integer, Map<String, Object>> parseWebXML() throws Exception {
21. Map<Integer, Map<String, Object>> result = new HashMap<Integer, Map<String,Object>>();
22. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
23. DocumentBuilder db = dbf.newDocumentBuilder();
24.  
25. InputStream in = XMLUtil.class.getClassLoader().getResourceAsStream("web.xml");
26. Document document = db.parse(in);
27. Element root = document.getDocumentElement();
28. NodeList xmlNodes = root.getChildNodes();
29. for (int i = 0; i < xmlNodes.getLength(); i++) {
30. Node config = xmlNodes.item(i);
31. if (null != config && config.getNodeType() == Node.ELEMENT_NODE) {
32. String nodeName1 = config.getNodeName();
33. if ("servlet".equals(nodeName1)) {
34. Map<String, Object> servletMaps = null;
35. if (result.containsKey(0)) {
36. servletMaps = result.get(0);
37. else {
38. servletMaps = new HashMap<String, Object>();
39. }
40.  
41. NodeList childNodes = config.getChildNodes();
42. Servlet servlet = new Servlet();
43. for (int j = 0; j < childNodes.getLength(); j++) {
44. Node node = childNodes.item(j);
45. if (null != node && node.getNodeType() == Node.ELEMENT_NODE) {
46. String nodeName2 = node.getNodeName();
47. String textContent = node.getTextContent();
48. if ("servlet-name".equals(nodeName2)) {
49. servlet.setName(textContent);
50. else if ("servlet-class".equals(nodeName2)) {
51. servlet.setClazz(textContent);
52. }
53. }
54. }
55. servletMaps.put(servlet.getName(), servlet);
56.  
57. result.put(0, servletMaps);
58. else if ("servlet-mapping".equals(nodeName1)) {
59. Map<String, Object> servletMappingMaps = null;
60. if (result.containsKey(1)) {
61. servletMappingMaps = result.get(1);
62. else {
63. servletMappingMaps = new HashMap<String, Object>();
64. }
65.  
66. NodeList childNodes = config.getChildNodes();
67. ServletMapping servletMapping = new ServletMapping();
68. for (int j = 0; j < childNodes.getLength(); j++) {
69. Node node = childNodes.item(j);
70. if (null != node && node.getNodeType() == Node.ELEMENT_NODE) {
71. String nodeName2 = node.getNodeName();
72. String textContent = node.getTextContent();
73. if ("servlet-name".equals(nodeName2)) {
74. servletMapping.setName(textContent);
75. else if ("url-pattern".equals(nodeName2)) {
76. servletMapping.setUrl(textContent);
77. }
78. }
79. }
80. servletMappingMaps.put(servletMapping.getUrl(), servletMapping);
81.  
82. result.put(1, servletMappingMaps);
83. }
84. }
85. }
86. return result;
87. }
88.  
89. public static void main(String[] args) throws Exception {
90. System.out.println(parseWebXML());
91. }
92. }
web.xml



01. <?xml version="1.0" encoding="UTF-8"?>
02. <web-app xmlns="http://java.sun.com/xml/ns/javaee"
03. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
05. version="2.5">
06.  
07. <servlet>
08. <servlet-name>cloud</servlet-name>
09. <servlet-class>com.cloud.tomcat.servlet.CloudServlet</servlet-class>
10. </servlet>
11.  
12. <servlet-mapping>
13. <servlet-name>cloud</servlet-name>
14. <url-pattern>/index</url-pattern>
15. </servlet-mapping>
16. </web-app>


运行结果:

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

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

得到如下结果:


 



 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值