Tomcat 源码解析 (二)自己写服务器
2013-04-15 18:55
429 查看
首先原谅我上次《How Tomcat Works 1》的粗制滥造, 这次给必要的代码都给上必要注释。
第二章是说明简单的servlet容器是如何工作的。这一章带有2个servlet容器应用,可以处
理静态资源和简单的servlet请求。尤其是你将会学到如何创建request和response对象,然
后把它们传递给被请求的servlet的service方法。在servlet容器里边还有一个servlet,你
可以从一个web浏览器中调用它。
一个基于java Web的服务器, 两个重中之重的类便是java.net.Socket 和 java.net.ServerSocket,
Socket即套接字,为了发送数据到另一台机器, 首先要知道那台机器的IP及套接字端口。
有更深入兴趣的可以继续深入了解Socket用法。
上面的Socket代表客户端套接字,那么同样的就应该有服务端的套接字:ServerSocket
我们这边使用的构造方法是 public ServerSocket(int port, int backLog, InetAddress bindingAddress);
port就是端口, backLog为输入连接指示(对连接的请求)的最大队列长度,我们这里设置为1,bindingAddress便是绑定地址,我们这里通过InetAddress.getByName("127.0.0.1")来获取。
另外我们还需要了解一下HTTP协议的基本概念:
一个HTTP请求包括三个组成部分:
方法—统一资源标识符(URI)—协议/版本
请求的头部
主体内容
下面是给一个栗子:
POST /examples/default.jsp HTTP/1.1
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: localhost
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
lastName=Franks&firstName=Michael
其中第一句包含了 method(POST), uri(/examples/default.jsp) 和version(HTTP/1.1)
然后最后一句便是请求主题(Body)
没错, 中间那长长的一坨就是http请求的头部(实际上请求主题可以很长,这边我们简化了)
更详细的可以看这篇文章 http 协议详解
我们要知道,servlet实现服务基本上要有3件事情要做:
1:Servlet;
通过service()方法接受和处理request, response
对于此, 我们创建类HttpServer:
2:Request;
包含http头等信息, 是javax.Servlet.http.ServletRequest 接口的实例
3:Response
通过service()处理赋值后,生成对于客户的响应,对应于Request,, 它是javax.Servlet.http.ServletResponse接口的实例
现在在项目文件夹下建立一个webroot文件夹:
先运行主程序HttpServer, 然后打开浏览器,输入地址:http://localhost:8080/index.html:
另外, 控制台结果显示了HTTP信息:
到此为止, 我们已经简单的了解到了一个简单web服务器是如何工作的。这一次仅仅由三个类组
成,所以并不是功能是十分局限的。下一次是真的要将要讨论动态内容的处理过程了
。。。。。。。
第二章是说明简单的servlet容器是如何工作的。这一章带有2个servlet容器应用,可以处
理静态资源和简单的servlet请求。尤其是你将会学到如何创建request和response对象,然
后把它们传递给被请求的servlet的service方法。在servlet容器里边还有一个servlet,你
可以从一个web浏览器中调用它。
一个基于java Web的服务器, 两个重中之重的类便是java.net.Socket 和 java.net.ServerSocket,
Socket即套接字,为了发送数据到另一台机器, 首先要知道那台机器的IP及套接字端口。
有更深入兴趣的可以继续深入了解Socket用法。
上面的Socket代表客户端套接字,那么同样的就应该有服务端的套接字:ServerSocket
我们这边使用的构造方法是 public ServerSocket(int port, int backLog, InetAddress bindingAddress);
port就是端口, backLog为输入连接指示(对连接的请求)的最大队列长度,我们这里设置为1,bindingAddress便是绑定地址,我们这里通过InetAddress.getByName("127.0.0.1")来获取。
另外我们还需要了解一下HTTP协议的基本概念:
一个HTTP请求包括三个组成部分:
方法—统一资源标识符(URI)—协议/版本
请求的头部
主体内容
下面是给一个栗子:
POST /examples/default.jsp HTTP/1.1
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: localhost
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
lastName=Franks&firstName=Michael
其中第一句包含了 method(POST), uri(/examples/default.jsp) 和version(HTTP/1.1)
然后最后一句便是请求主题(Body)
没错, 中间那长长的一坨就是http请求的头部(实际上请求主题可以很长,这边我们简化了)
更详细的可以看这篇文章 http 协议详解
我们要知道,servlet实现服务基本上要有3件事情要做:
1:Servlet;
通过service()方法接受和处理request, response
对于此, 我们创建类HttpServer:
package chap1_ASimpleWebServer; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; public class HttpServer { // getProperty("user.dir")就是返回当前目录, File.separator就是'\'; // 以博主机子为例, WEB_ROOT的内容就是"D:/workspace/howTomcatWorks/chap1_ASimpleWebServer/webroot" public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot"; // 如果要关闭服务器, 则在浏览器地址栏中输入 http://localhost:8080/SHUTDOWN private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; private boolean shutdown = false; // 类似Severlet.service(), 现在只是简单的了解下概念: public void await() { ServerSocket serverSocket = null; int port = 8080; try { // port就是端口, backLog为输入连接指示(对连接的请求)的最大队列长度,我们这里设置为1, // bindingAddress便是绑定地址,我们这里通过InetAddress.getByName("127.0.0.1")来获取。 serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } // loop waiting for a request while (!shutdown) { Socket socket = null; InputStream input = null; OutputStream output = null; try { // 先是通过ServerSocket实例 得到 Socket实例 socket = serverSocket.accept(); // 再通过Socket实例来获取InputStream和OutputStream的实例 input = socket.getInputStream(); output = socket.getOutputStream(); // create Request object & parse // 通过input创建request Request request = new Request(input); request.parse(); // create Response object // 通过request创建response Response response = new Response(output); response.setRequest(request); response.sendResource(); // close socket socket.close(); // check if the previous URI is a shutdown command shutdown = request.getUri().equals(SHUTDOWN_COMMAND); } catch (IOException e) { e.printStackTrace(); continue; } } } public static void main(String[] args) { System.out.println(WEB_ROOT); HttpServer server = new HttpServer(); server.await(); } }
2:Request;
包含http头等信息, 是javax.Servlet.http.ServletRequest 接口的实例
package chap1_ASimpleWebServer; import java.io.IOException; import java.io.InputStream; /* * 在这一章中,我们仅仅关注HTTP请求的第一部分,请求行。请求行从 * 一个方法标记开始,接下去是请求的URI和协议版本,最后是用回车换 * 行符(CRLF)结束。请求行里边的元素是通过一个空格来分隔的。例如, * 使用GET方法来请求index.html文件的请求行如下所示: * * GET /index.html HTTP/1.1 */ public class Request { private InputStream input; private String uri; public Request (InputStream input) { this.input = input; } public void parse() { // 新建StringBuffer request, 用于接收字节转化的字符 StringBuffer request = new StringBuffer(2048); int len; // 新建字节数组buffer, 用于接收套接字的InputStream字节流 byte[] buffer = new byte[2048]; try { len = input.read(buffer); } catch (IOException e) { e.printStackTrace(); len = -1; } for (int i = 0; i < len; i++) { // 这里不要忘了强制转型(byte -> char) request.append((char)buffer[i]); } System.out.println(request.toString()); // 得到URI的值 uri = parseUri(request.toString()); } // 从HTTP请求行里截取URI, 即 "GET /index.html HTTP/1.1" 中的 "/index.html" private String parseUri(String requestString) { int index1, index2; index1 = requestString.indexOf(' '); if (index1 != -1) { index2 = requestString.indexOf(' ', index1 + 1); if (index2 > index1) { return requestString.substring(index1 + 1, index2); } } return null; } // 返回URI public String getUri() { return uri; } }
3:Response
通过service()处理赋值后,生成对于客户的响应,对应于Request,, 它是javax.Servlet.http.ServletResponse接口的实例
package chap1_ASimpleWebServer; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; public class Response { // 设置默认响应信息长度 private static final int BUFFER_SIZE = 1024; Request request; OutputStream output; public Response (OutputStream output) { this.output = output; } public void setRequest(Request request) { this.request = request; } // 用来发送一个静态资源,例如一个HTML文件。它首先通过传递上一级 // 目录的路径和子路径给File累的构造方法来实例化java.io.File类 public void sendResource() throws IOException { // 创建byte数组bytes用于接收文件流数据 byte[] bytes = new byte[BUFFER_SIZE]; FileInputStream fis = null; try { // 根据当前目录和URI获取文件 File file = new File(HttpServer.WEB_ROOT, request.getUri()); if (file.exists()) { fis = new FileInputStream(file); int len = fis.read(bytes, 0, BUFFER_SIZE); while (len != -1) { // 写到output流中 output.write(bytes, 0, len); len = fis.read(bytes, 0, BUFFER_SIZE); } } else { // 如果文件不存在,页面提示File Not Found信息(404) String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "ContentType: text/html\r\n" + "ContentLength: 23\r\n\r\n" + "<head>File Not Found</head>"; output.write(errorMessage.getBytes()); } } catch (Exception e) { e.printStackTrace(); } finally { // 最后别忘记关闭文件流 if (fis != null) { fis.close(); } } } }
现在在项目文件夹下建立一个webroot文件夹:
先运行主程序HttpServer, 然后打开浏览器,输入地址:http://localhost:8080/index.html:
另外, 控制台结果显示了HTTP信息:
到此为止, 我们已经简单的了解到了一个简单web服务器是如何工作的。这一次仅仅由三个类组
成,所以并不是功能是十分局限的。下一次是真的要将要讨论动态内容的处理过程了
。。。。。。。
相关文章推荐
- Tomcat 源码解析 (二)自己写服务器
- 深入学习Tomcat----自己动手写服务器(附服务器源码)
- 深入学习Tomcat----自己动手写服务器(附服务器源码)
- 深入学习Tomcat----自己动手写服务器(附服务器源码)
- 深入学习Tomcat----自己动手写服务器(附服务器源码)
- 深入学习Tomcat----自己动手写服务器(附服务器源码)
- 深入学习Tomcat----自己动手写服务器(附服务器源码)
- [servlet]深入学习Tomcat----自己动手写服务器(附服务器源码)
- 深入学习Tomcat----自己动手写服务器(附服务器源码)
- 深入学习Tomcat-自己动手写服务器(附服务器源码)
- 深入学习Tomcat----自己动手写服务器(附服务器源码)
- 深入学习Tomcat----自己动手写服务器(附服务器源码)
- Tomcat源码解析-整体流程介绍
- Tomcat源码解析(一):wrapper
- android系统访问自己的tomcat服务器下的项目不能访问的原因
- tomcat源码解读一 Digester的解析方式
- 【Web容器】Tomcat源码分析(2)-server.xml文件的加载与解析
- tomcat源码解析(一)--启动与Server.xml文件的解析
- 如何利用自己的电脑做服务器发布tomcat的WEB项目供外网访问
- 深入学习Tomcat----自己动手写服务器