关于这篇文章也确实筹划了很久,今天决定开篇写第一篇,说起tomcat首先很容易联想到IIS,因为我最开始使用的就是.net技术,我第一次使用asp写学生成绩管理系统后,很茫然如何让别人都能看到或者说使用这个系统呢?由此认识了IIS,它是一个web容器,天生的多线程,及时响应用户提交的请求返回html页面,这就是我了解的最初的web容器的功能,由此我们来认识tomcat也并不困难,可以的话,在了解完tomcat后我们可以继续了解jboss、jetty等,好我们进入主题。

  我们在平时开发的过程中是在使用eclipse时候才启动tomcat,对于一个web容器而言,简而言之,它是系统的一个守护进程,守护着对这台服务器某个端口发起的请求,基于这一点,它就需要一个监听程序,这个监听程序来获取来自这个端口的特定请求的数据,ok,直接点讲,我们这里使用Socket来获取某个端口,通常是80端口的http请求,通过简单的Java

  程序的死循环(粗糙的做法,后面逐步优化)来实现不断的获取80端口http请求,来达到监听80端口http请求的目的。java.net包下面的Socket和ServerSocket两个类就能实现我们对8080端口的监听,去除中间的逻辑代码,我们只看这个两个类的演绎的话如下:

1 ServerSocket serverSocket = new ServerSocket(8080, 1, InetAddress.getByName("10.10.10.106"));

  对本机的8080端口进行监听

1 socket = serverSocket.accept();
2 input = socket.getInputStream();
3 output = socket.getOutputStream(); 

  以上代码就是获取监听结果。

  这是最简单和最精简的Socket通讯原理,基于这个核心点我们来开发一个简易的,可以提供静态页面访问的 custom tomcat,准备一个index.html文件放到/home/webroot目录下,那么除去拓展上面代码外,我们还需要一个Response和一个Request。

  类设计如下:

  HttpServer: 主函数所在类,负载启动ServerSocket和 操作整合Socket监听到的数据,以及返回结果,即操作Response和Request。

  Request: 封装Socket监听到的用户端请求,包括请求的http uri信息。

  Response: 封装需要推送到客户端的结果数据,即我们需要根据http uri 去本机寻找相应的资源,写给客户端。

  言简意赅,进入代码,首先 Request类代码:

 1 public class Request
 2 {
 3     private InputStream input;
 4     private String uri;
 5
 6     public Request(InputStream input) {
 7         this.input = input;
 8     }
 9
10     public void parse()
11     {
12         StringBuffer request = new StringBuffer(2048);
13         int i;
14         byte[] buffer = new byte[2048];
15         try
16         {
17              i = input.read(buffer);
18         }
19         catch(IOException e)
20         {
21              e.printStackTrace();
22              i = -1;
23         }
24
25         for (int j=0; j<i; j++)
26         {
27             request.append((char) buffer[j]);
28         }
29         System.out.print(request.toString());
30         uri = parseUri(request.toString());
31     }
32
33     private String parseUri(String requestString)
34     {
35         int index1, index2;
36         index1 = requestString.indexOf(' ');
37         if (index1 != -1) {
38             index2 = requestString.indexOf(' ', index1 + 1);
39             if (index2 > index1)
40                 return requestString.substring(index1 + 1, index2);
41             }
42         return null;
43     }
44
45     public String getUri()
46     {
47         return uri;
48     }
49 }

  代码解释:类包括一个属性和两个方法,input属性即是从Socket监听到的信息,Socket会将监听到的信息放入一个InputStream中,我们使用Reqeust类的Input属性来接受。接收到输入流后,在parse中对这个输入流进行解析成字符串,即对Http请求进行拆解,得到完整的Http URL,所以这个方法是私有的,是类存在意义的核心所在,而提供的对外方法parseUri是负载将parse解析的url结果提供给外界,即,客户端发来请求那个文件,具体的是最终提供给Response类,Response类得到这个文件名称后,去本地制定目录读取文件。Tomcat中通常就是webapps目录啦,很熟悉了吧,哈哈。

  Response类如何实现这个读取文件的历史使命呢,代码如下:

 1 public class Response {
 2
 3     private static final int BUFFER_SIZE = 1024;
 4     Request request;
 5     OutputStream output;
 6
 7     public Response(OutputStream output)
 8     {
 9         this.output = output;
10     }
11
12     public void setRequest(Request request)
13     {
14         this.request = request;
15     }
16
17     public void sendStaticResource() throws IOException
18     {
19         byte[] bytes = new byte[BUFFER_SIZE];
20         FileInputStream fis = null;
21         try
22         {
23                 File file = new File(HttpServer.WEB_ROOT, request.getUri());
24                 if (file.exists())
25                 {
26                         fis = new FileInputStream(file);
27                         int ch = fis.read(bytes, 0, BUFFER_SIZE);
28                         while (ch!=-1) {
29                             output.write(bytes, 0, ch);
30                             ch = fis.read(bytes, 0, BUFFER_SIZE);
31                         }
32                 }
33                 else
34                 {
35                     String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
36                         "Content-Type: text/html\r\n" +
37                         "Content-Length: 23\r\n" +
38                         "\r\n" +
39                         "<h1>File Not Found</h1>";
40                     output.write(errorMessage.getBytes());
41                 }
42         }
43         catch(Exception e)
44         {
45                 System.out.println(e.toString());
46         }
47         finally{
48             fis.close();
49         }
50
51     }
52 }

  代码解释:Response一共三个属性,一个方法。三个属性,一个是设置属性,BUFFER_SIZE设置读写字节流大小,关于读写文件,我个人觉得和服务器的性能和程序性能息息相关,不宜设定过大或过小(此处有不同见解的同仁欢迎来喷,我对这块理解目前限于此)。Reqeust属性,对照前文呼应,Response需要获取Request类的uri结果信息,所以这里放了一个Request属性,获取uri。Output,就不用说了,也是这个类存在的核心意义,依照Request类提供的uri信息,在本地读写文件后,形成一个输出来,存放到output中,那么这项工作就由sendStaticResource这个共有方法完成啦。

  好,代码到这个,可以说我们大家已经看到一个tomcat模型了,有点万事俱备,只欠东风的感觉,客户端发起请求,Response和Reqeust有了,那么继续往上游考虑,Reqeust依赖于客户端的请求,自然以来于Socket数据。我们在这里做得简便一点,将ServerSocket和Socket封装到一个HttpServer类中来,代码如下:

 1 public class HttpServer {
 2
 3     public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
 4     private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
 5     private boolean shutdown = false;
 6     public static void main(String[] args)
 7     {
 8         HttpServer httpServer = new HttpServer();
 9         httpServer.await();
10     }
11
12     public void await()
13     {
14         ServerSocket serverSocket = null;
15         Integer port = 8080;
16         try
17         {
18             serverSocket =  new ServerSocket(port, 1, InetAddress.getByName("10.10.10.106"));
19         }
20         catch(IOException e)
21         {
22             e.printStackTrace();
23             System.exit(1);
24         }
25
26         while(!shutdown)
27         {
28             Socket socket = null;
29             InputStream input = null;
30             OutputStream output = null;
31             try
32             {
33                 socket = serverSocket.accept();
34
35                 input = socket.getInputStream();
36                 output = socket.getOutputStream();
37                 Request request = new Request(input);
38                 request.parse();
39                 Response response = new Response(output);
40                 response.setRequest(request); response.sendStaticResource();  socket.close();
41                 shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
42             }
43             catch(Exception e)
44             {
45                 e.printStackTrace();continue;
46             }
47         }
48     }
49 }

  代码解释:我们知道启动tomcat之后,只要服务正常,客户端任意时候发起一个http请求,tomcat就会响应,那么这里我们肯定需要一个while循环来模拟不间断的监听,类await方法就是负责不断的获取socket监听到的结果,有立刻调动Reqeust和Response进行响应,加入主函数,为的是我们这个是模拟的控制台程序,需要一个程序入口,main函数就是程序入口。此外,HttpServer类包括一个静态属性SHUTDOWN_COMMAND,输入为true则停止这个main函数,变量初始值为false,当客户端也就是Request响应得到客户端输入 http://10.10.10.108:8080/SHUTDOWN时候,则变量在while中会置成true,紧接着停止main,结束应用程序进程。

  在eclipse中或者在命令行中启动这个main函数,命令行则是输入 java HttpServer.java。eclipse则是在main函数中右键 run as application启动。我们打开浏览器,输入 http://10.10.10.108:8080/index.html,回车结果如下:

  本地文件:

  

  好了,夜深啦,就此搁笔了,抛砖引玉,欢迎提议和讨论,这个系列会继续下去,直到一个完整的可以响应一个java action请求的custom tomcat产品出来。

  最后附上我的源代码:http://files.cnblogs.com/aspnetdream/Project.zip

  参考:《How tomcat works》 作者:Budi Kurniawan & Paul Deck

转载于:https://www.cnblogs.com/aspnetdream/p/4217581.html

试解析Tomcat运行原理(一)--- socket通讯相关推荐

  1. 试解析Tomcat运行原理(一)--- socket通讯(转)

    关于这篇文章也确实筹划了很久,今天决定开篇写第一篇,说起tomcat首先很容易联想到IIS,因为我最开始使用的就是.net技术,我第一次使用asp写学生成绩管理系统后,很茫然如何让别人都能看到或者说使 ...

  2. mybatis传递多个参数_深入浅出MyBatis:MyBatis解析和运行原理

    原文:https://juejin.im/post/5abcbd946fb9a028d1412efc 本篇文章是「深入浅出MyBatis:技术原理与实践」书籍的总结笔记. 上一篇介绍了反射和动态代理基 ...

  3. Tomcat运行原理(一)--- socket通讯

    说起tomcat首先很容易联想到IIS,由此认识了IIS,它是一个web容器,天生的多线程,及时响应用户提交的请求返回html页面,这就是我了解的最初的web容器的功能,由此我们来认识tomcat也并 ...

  4. python socket读取数据不能解析_通过实例解析return运行原理,除了quot;生孩子quot;python真是无所不能啊...

    文章内容主要介绍了通过实例解析Python return运行原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下!!! return 语句就是讲结果返 ...

  5. Tomcat 架构原理解析到架构设计借鉴

    ‍ 点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 Tomcat 架构原理解析到架构设计借鉴 Tomcat 发展这 ...

  6. 【Tomcat 】Tomcat 架构原理解析到架构设计借鉴

    Tomcat 发展这么多年,已经比较成熟稳定.在如今『追新求快』的时代,Tomcat 作为 Java Web 开发必备的工具似乎变成了『熟悉的陌生人』,难道说如今就没有必要深入学习它了么?学习它我们又 ...

  7. java与 C++ 之间进行 SOCKET 通讯要点简要解析

    Endian定义: 在计算机系统体系结构中用来描述在多字节数中各个字节的存储顺序. big-endian也称高位在前.大端在前.是 计算机体系结构中一种描述多字节存储顺序的术语,在这种机制中最重要字节 ...

  8. Mybatis运行原理及源码解析

    Mybatis源码解析 一.前言 本文旨在mybatis源码解析,将整个mybatis运行原理讲解清楚,本文代码地址: https://github.com/lchpersonal/mybatis-l ...

  9. spark启动的worker节点是localhost_Spark大数据在线培训:Spark运行原理解析

    在大数据技术框架当中,Spark是继Hadoop之后的又一代表性框架,也是学习大数据当中必学的重点技术框架.在这些年的发展当中,Spark所占据的市场地位,也在不断拓展.今天的Spark大数据在线培训 ...

最新文章

  1. windows 7 全屏游戏解决方案
  2. Spring Batch 基本的批处理指导原则
  3. 安全性神话已不再,首个MacOS勒索病毒现身
  4. React学习:双向数据绑定、约束性和非约束性组件-学习笔记
  5. Eclipse 内置浏览器
  6. linux ntp连接失败,linux ntp服务器连接异常
  7. 移动云亮相 2021 IDC 年度盛典 共话变革与赋能
  8. c语言怎么写贪吃蛇,刚学C语言,想写一个贪吃蛇的代码
  9. Bootstrap3 表单支持的控件
  10. 删除U盘时提示无法停止‘通用卷’设备的解决方法
  11. vue http get html模板,怎么用vue.js做异步请求?
  12. settimeout在各个浏览器的最小时间
  13. MAX30102+usb转串口+树莓派
  14. 聊天机器人-基于QQ聊天记录训练
  15. 【渝粤题库】国家开放大学2021春2409中国古代文学(B)(1)题目
  16. 王阳明:<二> 立志,勤学,改过,责善
  17. iOS工程师 - 简历
  18. 谈谈 跨境劳工的噩梦深坑。
  19. Windows7 tls加密协议设置导致的邮件收发问题 WLM 0x800CCC0B、0x800CCC0F
  20. 嵌入式开发学习(5)S5PV210开发板刷系统那点破事儿之一

热门文章

  1. 数组的冒泡排序快速上手
  2. 分配任务的代码PHP,php计划任务的示例代码分享
  3. python技巧 pdf-求教使用python库提取pdf的方法?
  4. android 隐藏所有 fragment,Android 隐藏Fragment
  5. ts 变量后面加问号或者叹号_关于记录型信号量与TS指令的理解
  6. linux动态可执行文件,Linux中ELF格式 可执行文件+动态链接器 的加载
  7. java getselectedrow_Java Swing实现展示数据,以及过滤排序
  8. python标签打印工具_NiceLabel Designer 2017条码标签打印软件
  9. java获取列族的列_在cassandra-cli中如何获取表中的所有列名以及如何在java中使用hector获取它?...
  10. python 购物车程序_Python 购物车程序(文件版)