Tomcat源码学习记录--web服务器初步认识
Tomcat作为开源的轻量级WEB服务器,虽然不是很适合某些大型项目,但是它开源,读其源代码可以很好的提高我们的编程功底和设计思维。Tomcat中用到了很多比较好的设计模式,其中代码风格也很值得我们去效仿。前阵子看了Tomcat源码分析这本书,特此过来分享分享自己的学习过程记录。说得不好,大神不要喷我。也不废话了,直入主题上代码。Tomcat是什么,Tomcat是一个web服务器,能够接收请求,作出响应。接收请求,作出响应让我们联想到Socket编程。我们可以起一个线程服务ServerSocket来监听本机的8080端口(可配置),然后就可以在浏览器上访问http://localhost:8080/index.html,这个时候就可以通过socket的inputstream获取到浏览器封装的HTTP请求了,然后就可以针对这个请求来大做文章。以下是服务端的代码
1 package cn.tim.server.core;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.OutputStream;
7 import java.net.InetAddress;
8 import java.net.ServerSocket;
9 import java.net.Socket;
10
11
12 /**
13* HTTP服务器,主类
14* @author TIM
15*
16*/
17 public class HttpServer {
18
19
20 /**
21 * 端口
22 */
23 public int PORT = 8080;
24
25
26 /**
27 * 关闭指令
28 */
29 public final static String SHUTDOWN = "SHUTDOWN";
30
31
32 /**
33 * webroot根目录
34 */
35 public static final String WEB_ROOT =
36 System.getProperty("user.dir") + File.separator + "WebRoot";
37
38
39 public static void main(String[] args) {
40
41 new HttpServer().await();
42
43 }
44
45
46 /**
47 * 线程监听
48 */
49 private void await() {
50
51 ServerSocket server = null;
52 try {
53 server = new ServerSocket(PORT,1,
54 InetAddress.getByName("127.0.0.1"));
55 } catch (Exception e) {
56 e.printStackTrace();
57 }
58
59 boolean shutdown = false;
60 while(!shutdown) {
61 Socket client = null;
62 InputStream in = null;
63 OutputStream out = null;
64 try {
65 // 获取到请求socket
66 client = server.accept();
67 in = client.getInputStream();
68 out = client.getOutputStream();
69
70 // 生成request同时解析请求
71 Request request = new Request(in);
72 request.parse();
73
74 // 生成response
75 Response response = new Response(out);
76 response.setRequest(request);
77 // 根据资源定位符发送对应资源
78 response.sendStaticResource();
79 client.close();
80
81 shutdown = request.getUri().equals(SHUTDOWN);
82 } catch (IOException e) {
83 // TODO Auto-generated catch block
84 e.printStackTrace();
85 continue;
86 }
87
88 }
89
90 }
91
92 }
既然服务端HttpServer都出来了,Request都干些什么,request顾名思义,请求肯定是封装请求的一个JAVA类,肯定要能够解析HTTP请求,例如访问静态资源,就得获取到静态资源的资源定位符uri。
HTTP请求Request类:
1 GET /index.html HTTP/1.1
2 Accept: text/html, application/xhtml+xml, */*
3 Accept-Language: zh-CN
4 User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MALCJS)
5 Accept-Encoding: gzip, deflate
6 Host: localhost:8080
7 DNT: 1
8 Connection: Keep-Alive
9 Cookie: principal=user:admin__password:admin
1 package cn.tim.server.core;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 /**
7* 封装请求
8* @author TIM
9*
10*/
11 public class Request {
12
13
14 /**
15 * 请求输入流
16 */
17 private InputStream in;
18
19
20 /**
21 * 资源定位符
22 */
23 private String uri;
24
25
26 /**
27 * 初始化request,传入socket输入流
28 * @param in
29 */
30 public Request(InputStream in) {
31 this.in = in;
32 }
33
34
35 /**
36 * 根据请求字符串解析请求
37 */
38 public void parse() {
39
40 try {
41 byte[] bytes = new byte;
42 int i = in.read(bytes);
43
44 StringBuffer buffer = new StringBuffer(2048);
45 for(int j=0; jindex1) {
69 return requestString.substring(index1+1, index2);
70 }
71 }
72 return null;
73 }
74
75
76 public InputStream getIn() {
77 return in;
78 }
79
80
81 public String getUri() {
82 return uri;
83 }
84
85 }
获取到资源定位符,接下来就是根据资源定位符来作出相应,当然实际的Tomcat处理方式肯定是很复杂的,我们只模仿其中简单的方式,访问静态资源。
Response类:
1 package cn.tim.server.core;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.OutputStream;
8
9 public class Response {
10
11
12 /**
13 * 输出
14 */
15 private OutputStream out;
16
17
18 /**
19 * 缓冲大小
20 */
21 public final static int BUFFER_SIZE = 2048;
22
23
24 /**
25 * 请求,根据请求作出对应的响应
26 */
27 private Request request;
28
29
30 public Response(OutputStream out) {
31 this.out = out;
32 }
33
34
35 /**
36 * 发送静态资源
37 */
38 public void sendStaticResource() {
39
40 byte[] bytes = new byte;
41 InputStream in = null;
42 try {
43 File file = new File(HttpServer.WEB_ROOT, request.getUri());
44 // 请求的资源存在
45 if(file.exists()) {
46 in = new FileInputStream(file);
47 int ch;
48 if((ch=in.read(bytes, 0, BUFFER_SIZE))!=-1) {
49 out.write(bytes, 0, ch);
50 }
51 }
52 // 请求资源不存在报404
53 else {
54 String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
55 "Content-Type: text/html\r\n" +
56 "Content-Length: 23\r\n" +
57 "\r\n" +
58 "File Not Found";
59 out.write(errorMessage.getBytes());
60 }
61 } catch (Exception e) {
62 // TODO Auto-generated catch block
63 e.printStackTrace();
64 } finally {
65 if(in!=null)
66 try {
67 in.close();
68 } catch (IOException e) {
69 // TODO Auto-generated catch block
70 e.printStackTrace();
71 }
72 }
73
74 }
75
76
77 public void setRequest(Request request) {
78 this.request = request;
79 }
80
81 }
这样,一个简单的Web服务器就实现了,可以访问静态资源,直接在浏览器上访问,没有找到对应的资源还可以报404错误。今天就写到这里,继续努力。。。
页:
[1]