Tomcat最初是由Sun的软件架构师詹姆斯·邓肯·戴维森开发的。后来他帮助将其变为开源项目,并由Sun贡献给Apache软件基金会,并且成为Jakarta 项目中的一个核心项目。因此逐渐成为世界上广泛使用的支持jsp和servlets的Web服务器。

声明:

1:本系列仅记录本人读<<深入剖析Tomcat>>此书的一些感悟,不足之处,留言指正,不胜感激。

2:本系列所有代码参照<<深入剖析Tomcat>>,不对之处,留言指正,不胜感激。 概念:传送门:tomcat百度百科,这里说一个点,tomcat是轻量级的javaweb服务器,用于处理servlet/jsp等动态网页,虽说也可以处理静态网页,但相比apache而言还是逊色不少。有兴趣的朋友可以另行了解一下 nginx, iis,apache等其他较为流行的web服务器。 使用过tomcat的朋友应该知道,当java web项目部署到tomcat后

在浏览器地址栏里输入:http://localhost:8080/资源路径,便可以访问项目资源。在这一过程中,tomcat扮演调度中心的角色,接收浏览器发起资源请求并解析,根据解析结果分发给指定web项目处理,然后根据处理结果,对浏览器响应。对此,我们来研究一下,tomcat是怎么做到的。项目结构:

MyTomcat 接收请求(Request) 想接收浏览发起的请求,需要做几手准备, 1:监听端口(8080), 2:接收浏览器连接(socket连接) 3:解析HTTP请求数据。下面是代码模拟:

  1. 第一第二步: 使用httpServer模拟tomcat调度中心
  2. /**
  3. * 模拟tomcat的核心类
  4. */public class HttpServer {
  5. //tomcat项目绝对路径, 所有web项目都丢在webapps目录下
  6. public static final String WEB_ROOT =
  7. System.getProperty("user.dir") + File.separator + "webapps";
  8. // 模拟tomcat关闭命令
  9. private static final String SHUTDOWN_CMD = "/SHUTDOWN";
  10. private boolean shutdown = false;
  11. //持续监听端口
  12. @SuppressWarnings("resource")
  13. public void accept() {
  14. ServerSocket serverSocket = null;
  15. try {
  16. // 启动socket服务, 监听8080端口,
  17. serverSocket = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
  18. } catch (IOException e) {
  19. e.printStackTrace();
  20. throw new RuntimeException("启动myTomcat服务器失败:" + e.getMessage(), e);
  21. }
  22. // 没接收到关闭命令前一直监听
  23. while (!shutdown) {
  24. Socket socket = null;
  25. InputStream in = null;
  26. OutputStream out = null;
  27. try {
  28. // 接收请求
  29. socket = serverSocket.accept();
  30. in = socket.getInputStream();
  31. out = socket.getOutputStream();
  32. // 将浏览器发送的请求信息封装成请求对象
  33. Request request = new Request(in);
  34. request.parseRequest();
  35. // 将相应信息封装相应对象
  36. //此处简单响应一个静态资源文件
  37. Response response = new Response(out);
  38. //模拟页面跳转
  39. response.sendRedircet(request.getUri());
  40. socket.close();
  41. //如果是使用关闭命令,停止监听退出
  42. shutdown = request.getUri().equals(SHUTDOWN_CMD);
  43. } catch (Exception e) {
  44. e.printStackTrace();
  45. continue;
  46. }
  47. }
  48. }
  49. public static void main(String[] args) {
  50. new HttpServer().accept();
  51. }
  52. }
  53. 第三步,使用HttpReqeust封装请求相关信息
  54. /**
  55. * 请求信息封装对象
  56. */public class Request {
  57. // 浏览器socket连接的读流
  58. private InputStream in;
  59. //请求行信息信息中的uri
  60. private String uri;
  61. public Request(InputStream in) {
  62. this.in = in;
  63. }
  64. // 解析浏览器发起的请求
  65. public void parseRequest() {
  66. // 暂时忽略文件上传的请求,假设都字符型请求
  67. byte[] buff = new byte[2048];
  68. StringBuffer sb = new StringBuffer(2048);
  69. int len = 0;
  70. //请求内容
  71. try {
  72. len = in.read(buff);
  73. sb.append(new String(buff, 0, len));
  74. } catch (IOException e) {
  75. e.printStackTrace();
  76. }
  77. System.out.print(sb.toString());
  78. //解析请求行中uri信息
  79. uri = this.parseUri(sb.toString());
  80. }
  81. /**tomcat接收浏览器发起的请求是居于http协议的,请求内容格式:*/
  82. /**请求行:请求方式 请求uri 协议版本*/
  83. //GET /index HTTP/1.1
  84. /**请求头:以key-value形式存在*/
  85. //Host: localhost:8080
  86. //Connection: keep-alive
  87. //Upgrade-Insecure-Requests: 1
  88. //User-Agent: Mozilla/5.0 .........
  89. //Accept: text/html,application/xhtml+xml......
  90. //Accept-Encoding: gzip, deflate, br
  91. //Accept-Language: zh-CN,zh;q=0.9
  92. //Cookie: .....
  93. /**请求体: 请求头回车格一行就是请求体,get方式请求体为空*/
  94. public String parseUri(String httpContent) {
  95. //传入的内容解析第一行的请求行即可:
  96. //请求行格式: 请求方式 请求uri 协议版本 3个内容以空格隔开
  97. int beginIndex = httpContent.indexOf(" ");
  98. int endIndex;
  99. if(beginIndex > -1) {
  100. endIndex = httpContent.indexOf(" ", beginIndex + 1);
  101. if(endIndex > beginIndex) {
  102. return httpContent.substring(beginIndex, endIndex).trim();
  103. }
  104. }
  105. return null;
  106. }
  107. public String getUri() {
  108. return uri;
  109. }
  110. }
  111. 假设,浏览器发起请求:http://localhost:8080/hello/index.html HttpServer中socket通过输入流获取到的数据是:
  112. GET /hello/index.html HTTP/1.1
  113. Host: localhost:8080
  114. Connection: keep-alive
  115. Upgrade-Insecure-Requests: 1
  116. User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
  117. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
  118. Accept-Encoding: gzip, deflate, br
  119. Accept-Language: zh-CN,zh;q=0.9
  120. Cookie: Hm_lvt_aa5c701f4f646931bf78b6f40b234ef5=1516445118,1516604544,1518416964,1518497222; JSESSIONID=79367FD9A55B9B442C4ED112D10FDAC5
  121. HttpServer 将上述的数据交于HttpRequest对象处理,该对象调用parseRequest解析,获取请求行中的uri 数据, 分析该数据, 得到上下文路径,项目名,资源名。统称资源路径。
  122. 上面数据得到: hello 项目下, index.html 资源(没有上下文路径)
  123. 响应请求
  124. 当从请求信息中获取uri后,进而获取到hello 项目, index.html资源, 响应请求就可以简单认为根据资源路径查找资源,如果找到,使用socket output流直接输出资源数据即可,如果找不到,输出404信息。
  125. * 处理响应请求对象
  126. public class Response {
  127. // 浏览器socket连接的写流
  128. private OutputStream out;
  129. public Response(OutputStream out) {
  130. this.out = out;
  131. }
  132. public OutputStream getOutputStream() {
  133. return out;
  134. }
  135. //跳转
  136. public void sendRedircet(String uri) {
  137. File webPage = new File(HttpServer.WEB_ROOT, uri);
  138. FileInputStream fis = null;
  139. StringBuffer sb = new StringBuffer();
  140. try {
  141. //找得到页面是
  142. if(webPage.exists()&& webPage.isFile()) {
  143. String respHeader = "HTTP/1.1 200 OK\r\n" +
  144. "Content-Type: text/html\r\n" +
  145. "Content-Length: #{count}\r\n" +
  146. "\r\n";
  147. fis = new FileInputStream(webPage);
  148. byte[] buff = new byte[2048];
  149. int len = 0;
  150. while( (len = fis.read(buff))!= -1) {
  151. sb.append(new String(buff, 0, len));
  152. }
  153. respHeader=respHeader.replace("#{count}", sb.length()+"");
  154. System.out.println(respHeader + sb);
  155. out.write((respHeader + sb).getBytes());
  156. }else {
  157. //页面找不到时
  158. String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
  159. "Content-Type: text/html\r\n" +
  160. "Content-Length: 23\r\n" +
  161. "\r\n" +
  162. "<h1>File Not Found</h1>";
  163. out.write(errorMessage.getBytes());
  164. }
  165. } catch (Exception e) {
  166. e.printStackTrace();
  167. } finally {
  168. try {
  169. if (fis != null) {
  170. fis.close();
  171. }
  172. } catch (IOException e) {
  173. e.printStackTrace();
  174. }
  175. }
  176. }
  177. }

探索免费开源服务器tomcat的魅力的更多相关文章

  1. Scut游戏服务器免费开源框架-3

    Scut游戏服务器免费开源框架--快速开发(3) Scut快速开发(3) 1        开发环境 需要安装的软件 a)        消息队列 b)        数据库,Sql2005以上版本 ...

  2. web服务器tomcat入门实战

    一.tomcat介绍1.1 引入tomcat Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Su ...

  3. 服务器Tomcat WAS JBoss

    做任何web项目,都离不开服务器,有钱的公司用WebSphere.WebLogic,没钱公司用nginx+tomcat,不要小瞧nginx+tomcat麻雀虽小,五脏俱全. 服务器的知识,在笔试.面试 ...

  4. 免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)

    前面介绍了六种.NET组件,其中有一种组件是写文件的压缩和解压,现在介绍另一种文件的解压缩组件SharpZipLib.在这个组件介绍系列中,只为简单的介绍组件的背景和简单的应用,读者在阅读时可以结合官 ...

  5. 免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)

    很多的软件项目中都会使用到定时任务.定时轮询数据库同步,定时邮件通知等功能..NET Framework具有“内置”定时器功能,通过System.Timers.Timer类.在使用Timer类需要面对 ...

  6. 【转】免费开源的FTP软件,FileZilla

    原文网址:http://baike.baidu.com/view/670329.htm?fr=aladdin FileZilla FileZilla是一个免费开源的FTP软件,分为客户端版本和服务器版 ...

  7. java web服务器tomcat介绍【转载】

    机器矩阵2016-08-10 22:14 java程序员亲切地称他为tom猫,看到这只猫可以说明1 服务器部署成功了 ,2 网络是联通的. 到底这只猫是什么来头呢? tomcat是Apache基金会下 ...

  8. 如何通过免费开源ERP Odoo建立你的团队, 销售过程和目标

    这种快速的一步一步的指南将引导您完成Odoo CRM, 帮助您轻松处理您的销售渠道, 时刻从线索到客户管理您的销售渠道. 配置 从 Odoo初始化后,生成你的数据库, 选择CRM 作为第一个app安装 ...

  9. Odoo:全球第一免费开源ERP权威性能测试报告完整版(绝对珍藏)

    Odoo平台简介 Odoo(以前叫OpenERP)是世界排名第一的开源ERP系统,最早由比利时一家公司开发,经过十几年发展,目前全世界Odoo的使用者超过2百万人,Odoo被翻译成几十种语言,Odoo ...

随机推荐

  1. Hibernate缓存简介和对比、一级缓存、二级缓存详解

    一.hibernate缓存简介 缓存的范围分为3类:  1.事务范围(单Session即一级缓存)     事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象 ...

  2. 服务端高并发分布式架构演进之路 转载,原文地址:https://segmentfault.com/a/1190000018626163

    1. 概述 本文以淘宝作为例子,介绍从一百个到千万级并发情况下服务端的架构的演进过程,同时列举出每个演进阶段会遇到的相关技术,让大家对架构的演进有一个整体的认知,文章最后汇总了一些架构设计的原则. 特 ...

  3. select2实现多选 并且回显

    html代码:<select name="ruleId" id="ruleId" class="required" onchange= ...

  4. Vue --- 指令练习

    scores = [ { name: 'Bob', math: 97, chinese: 89, english: 67 }, { name: 'Tom', math: 67, chinese: 52 ...

  5. 安装cuda及之后更新环境变量的方法

    安装参考:https://www.cnblogs.com/fanfzj/p/8521728.html 更新环境变量: 将 CUDA.CUPTI 和 cuDNN 安装目录添加到 %PATH% 环境变量中 ...

  6. 英语听力,如何成为更好的交谈着https://www.bilibili.com/video/av4279405?from=search&seid=5889429711390689339

    and how many of you know at least one person that you because you just do not want to talk to them.y ...

  7. SpringBoot之使用Druid连接池,SQL监控和spring监控

    项目结构 1.引入maven依赖 <dependencies> <dependency> <groupId>org.springframework.boot< ...

  8. LOJ P10015 扩散 题解

    每日一题 day49 打卡 Analysis 用dis数组记录每两个点之间的时间,再用一个传递闭包来维护最小的时间就好了 #include<iostream> #include<cs ...

  9. UFUN函数 UF_ATTR函数(UF_ATTR_assign ,UF_ATTR_read_value )

    UF_initialize(); tag_t ; ]="零件名称"; UF_ATTR_value_t value; value.type=UF_ATTR_string; value ...

  10. Lightning Web Components 开发指南(二)

    Lightning Web Components 是自定义元素使用html 以及现代javascript进行构建. Lightning Web Components UI 框架使用web compon ...