Tomcat作為開源的輕量級(jí)WEB服務(wù)器,雖然不是很適合某些大型項(xiàng)目,但是它開源,讀其源代碼可以很好的提高我們的編程功底和設(shè)計(jì)思維。Tomcat中用到了很多比較好的設(shè)計(jì)模式,其中代碼風(fēng)格也很值得我們?nèi)バХ隆G瓣囎涌戳薚omcat源碼分析這本書,特此過來分享分享自己的學(xué)習(xí)過程記錄。說得不好,大神不要噴我。
也不廢話了,直入主題上代碼。Tomcat是什么,Tomcat是一個(gè)web服務(wù)器,能夠接收請(qǐng)求,作出響應(yīng)。接收請(qǐng)求,作出響應(yīng)讓我們聯(lián)想到Socket編程。我們可以起一個(gè)線程服務(wù)ServerSocket來監(jiān)聽本機(jī)的8080端口(可配置),然后就可以在瀏覽器上訪問http://localhost:8080/index.html,這個(gè)時(shí)候就可以通過socket的inputstream獲取到瀏覽器封裝的HTTP請(qǐng)求了,然后就可以針對(duì)這個(gè)請(qǐng)求來大做文章。以下是服務(wù)端的代碼
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服務(wù)器,主類
14
*
@author
TIM
15
*
16
*/
17
public
class
HttpServer {
18
19
20
/**
21
* 端口
22
*/
23
public
int
PORT = 8080
;
24
25
26
/**
27
* 關(guān)閉指令
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
* 線程監(jiān)聽
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
//
獲取到請(qǐng)求socket
66
client =
server.accept();
67
in =
client.getInputStream();
68
out =
client.getOutputStream();
69
70
//
生成request同時(shí)解析請(qǐng)求
71
Request request =
new
Request(in);
72
request.parse();
73
74
//
生成response
75
Response response =
new
Response(out);
76
response.setRequest(request);
77
//
根據(jù)資源定位符發(fā)送對(duì)應(yīng)資源
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
}
既然服務(wù)端HttpServer都出來了,Request都干些什么,request顧名思義,請(qǐng)求肯定是封裝請(qǐng)求的一個(gè)JAVA類,肯定要能夠解析HTTP請(qǐng)求,例如訪問靜態(tài)資源,就得獲取到靜態(tài)資源的資源定位符uri。
HTTP請(qǐng)求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
* 封裝請(qǐng)求
8
*
@author
TIM
9
*
10
*/
11
public
class
Request {
12
13
14
/**
15
* 請(qǐng)求輸入流
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
* 根據(jù)請(qǐng)求字符串解析請(qǐng)求
37
*/
38
public
void
parse() {
39
40
try
{
41
byte
[] bytes =
new
byte
[2048
];
42
int
i =
in.read(bytes);
43
44
StringBuffer buffer =
new
StringBuffer(2048
);
45
for
(
int
j=0; j<i; j++
) {
46
buffer.append((
char
)bytes[j]);
47
}
48
System.out.println(buffer.toString());
49
uri =
parseUri(buffer.toString());
50
System.out.println(uri);
51
}
catch
(IOException e) {
52
//
TODO Auto-generated catch block
53
e.printStackTrace();
54
}
55
56
}
57
58
59
/**
60
* 解析出資源定位符uri,實(shí)際上就是用字符串分拆獲取到GET /index.html HTTP/1.1中的/index,html
61
*
@return
62
*/
63
private
String parseUri(String requestString) {
64
65
int
index1 = requestString.indexOf(" "
);
66
if
(index1 != -1
) {
67
int
index2 = requestString.indexOf(" ", index1+1
);
68
if
(index2>
index1) {
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
}
獲取到資源定位符,接下來就是根據(jù)資源定位符來作出相應(yīng),當(dāng)然實(shí)際的Tomcat處理方式肯定是很復(fù)雜的,我們只模仿其中簡(jiǎn)單的方式,訪問靜態(tài)資源。
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
* 請(qǐng)求,根據(jù)請(qǐng)求作出對(duì)應(yīng)的響應(yīng)
26
*/
27
private
Request request;
28
29
30
public
Response(OutputStream out) {
31
this
.out =
out;
32
}
33
34
35
/**
36
* 發(fā)送靜態(tài)資源
37
*/
38
public
void
sendStaticResource() {
39
40
byte
[] bytes =
new
byte
[BUFFER_SIZE];
41
InputStream in =
null
;
42
try
{
43
File file =
new
File(HttpServer.WEB_ROOT, request.getUri());
44
//
請(qǐng)求的資源存在
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
//
請(qǐng)求資源不存在報(bào)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
"<h1>File Not Found</h1>"
;
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
}
這樣,一個(gè)簡(jiǎn)單的Web服務(wù)器就實(shí)現(xiàn)了,可以訪問靜態(tài)資源,直接在瀏覽器上訪問,沒有找到對(duì)應(yīng)的資源還可以報(bào)404錯(cuò)誤。今天就寫到這里,繼續(xù)努力。。。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

