关于这篇文章也确实筹划了很久,今天决定开篇写第一篇,说起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

http://www.cnblogs.com/aspnetdream/p/4217581.html

试解析Tomcat运行原理(一)--- socket通讯(转)的更多相关文章

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

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

  2. 互联网轻量级框架SSM-查缺补漏第七天(MyBatis的解析和运行原理)

    第七章MyBatis的解析和运行原理 SqlSessionFactory是MyBatis的核心类之一,其最重要的功能就是提供创建MyBatis的核心借口SqlSession,所以要先创建SqlSess ...

  3. Mybatis的解析和运行原理

    Mybatis的解析和运行原理 Mybatis的运行过程大致分为两大步:第一步,读取配置文件缓存到Configuration对象,用以创建 SqlSessionFactory:第二步,SqlSessi ...

  4. .NET/ASP.NET MVC Controller 控制器(深入解析控制器运行原理)

    阅读目录: 1.开篇介绍 2.ASP.NETMVC Controller 控制器的入口(Controller的执行流程) 3.ASP.NETMVC Controller 控制器的入口(Controll ...

  5. 二、ASP.NET MVC Controller 控制器(一:深入解析控制器运行原理)

    阅读目录: 1.开篇介绍 2.ASP.NETMVC Controller 控制器的入口(Controller的执行流程) 3.ASP.NETMVC Controller 控制器的入口(Controll ...

  6. NET/ASP.NET MVC Controller 控制器(一:深入解析控制器运行原理)

    阅读目录: 1.开篇介绍 2.ASP.NETMVC Controller 控制器的入口(Controller的执行流程) 3.ASP.NETMVC Controller 控制器的入口(Controll ...

  7. 《深入浅出MyBatis技术原理与实战》——6. MyBatis的解析和运行原理

    MyBatis的运行分为两大部分,第一部分是读取配置文件缓存到Configuration对象,用以创建SqlSessionFactory,第二部分是SqlSession的执行过程. 6.1 涉及的技术 ...

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

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

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

    原文链接: http://blog.csdn.net/hslinux/article/details/6214594 java与C++之间进行SOCKET通讯要点简要解析 hslinux 0.篇外语 ...

随机推荐

  1. 介绍一款开源的类Excel电子表格软件

     Excel一直以霸主的地位,占领了Windows桌面表格软件市场No 1,与此同一时候,Office套装产品差点儿成为了IT行业的标配办公技能.有无相似Excel的桌面程序,绿色版,实现主要的数 ...

  2. unix ls命令

    [语法]: ls  [-RadCxmlnogrtucpFbqisf1]   [文件夹或文件......] [说明]: ls 命令列出指定文件夹下的文件,缺省文件夹为当前文件夹 ./,缺省输出顺序为纵向 ...

  3. Read and Write NSArray, NSDictionary and NSSet to a File

    查询地址:http://iosdevelopertips.com/data-file-management/read-and-write-nsarray-nsdictionary-and-nsset- ...

  4. Android:mimeType

    接收从其他应用传过来的数据,要用到清单文件 <activity android:name="com.terry.myActivity2" android:label=&quo ...

  5. Android的回调

    学了两三周的安卓了,最先开始是看mars老师的视频,看了一两天结合慕课网上的一些安卓视频,到现在算是有点入门了. 安卓立用得比较多的回调函数有点不明是怎么实现的,网上找了一些资料,结合自己的实践,总算 ...

  6. MYSQL 备份用户权限

    MYSQL 备份用户权限 datadbblack 192.168.1.10 是 SELECT, RELOAD, SHOW DATABASES, LOCK TABLES  否 权限列表 1.Select ...

  7. ZOJ 3601 Unrequited Love 【STL__pair_的应用】

    下面这个例子就是 STL:pair 的用法 #include <iostream> #include <utility> #include <string> usi ...

  8. DE1-SOC连接设定

    将电源供应器插上电源接口. 使用白色的USB Type B线材将计算机与DE1-SoC上的USB-Blaster II接口连接.此接口主要负责FPGA配置以及HPS Debug使用. 使用Mini-U ...

  9. Android 改变窗口标题栏的布局

    Android改变窗口标题栏的布局  第一种方式 --在XML文件里面引入配置文件作为标题. 第二种方式  --动态的代码加入进去. 第三种方式(网上的): 一. 重点 一般应用的Title都是建立应 ...

  10. android的animator

    3.0 以前,android支持两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画系统:property animation,这 ...