Cyh的博客
Email:kissyan4916@163.com
posts - 26, comments - 19, trackbacks - 0, articles - 220
導航
BlogJava
首頁
新隨筆
聯系
聚合
管理
公告
一直努力努力努力,像奴隸奴隸奴隸!~~
<
2025年6月
>
日
一
二
三
四
五
六
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
常用鏈接
我的隨筆
我的文章
我的評論
我的參與
最新評論
隨筆檔案
(25)
2011年5月 (1)
2010年4月 (12)
2010年1月 (1)
2009年12月 (2)
2009年6月 (1)
2009年4月 (4)
2009年2月 (4)
文章分類
(219)
Android(26)
DB(5)
J2EE(31)
J2SE(79)
JavaScript(15)
others(47)
SOA&Web Service(1)
中間件(1)
軟件工程(12)
軟件架構(2)
文章檔案
(220)
2011年8月 (1)
2010年12月 (23)
2010年11月 (2)
2010年8月 (5)
2010年7月 (2)
2010年6月 (2)
2010年5月 (1)
2010年4月 (12)
2010年3月 (28)
2010年2月 (5)
2010年1月 (23)
2009年12月 (39)
2009年6月 (14)
2009年5月 (31)
2009年3月 (2)
2009年2月 (29)
2009年1月 (1)
新聞檔案
(66)
2010年10月 (1)
2010年9月 (5)
2010年8月 (11)
2010年7月 (21)
2010年6月 (13)
2010年5月 (8)
2010年4月 (5)
2009年11月 (2)
相冊
Ryan
收藏夾
(7)
JAVA(7)
最新隨筆
1.?集成FCKeditor 3.5.3
2.?android自適應屏幕方向和大小
3.?Android游戲開發之旅(二十) 雙按事件捕獲
4.?Android游戲開發之旅(十八) SoundPool類
5.?Android游戲開發之旅(十九) 分辨率大全
6.?Android游戲開發之旅(十七) 圖像漸變特效
7.?Android游戲開發之旅(十六) 異步音樂播放
8.? Android游戲開發之旅(十四) 游戲開發實戰一
9.?Android游戲開發之旅(十五) 按鍵中斷處理
10.?Android游戲開發之旅(十二)Sensor重力感應(2)
搜索
最新評論
1.?re: struts2 checkboxlist標簽的使用
同居同意同意
--yuk
2.?re: struts2 checkboxlist標簽的使用
ss
--d
3.?re: JavaMail(4)--使用POP3接收郵件
郵件信息可以打印出來,可是下載郵件會出錯是什么原因?
--琳喵喵0721
4.?re: JavaMail(4)--使用POP3接收郵件
評論內容較長,點擊標題查看
--流風
5.?re: 操作PDF文件
評論內容較長,點擊標題查看
--ly.wolf
閱讀排行榜
1.?struts2 checkboxlist標簽的使用(18237)
2.?struts2異常攔截器(5866)
3.?struts2迭代標簽(3851)
4.?用freemind 秒殺Spring Security(1923)
5.?加載順序會影響對spring bean 的調用。(1493)
網絡編程>>HTTP服務器
Posted on 2009-12-12 16:22
啥都寫點
閱讀(330)
評論(0)
編輯
收藏
所屬分類:
J2SE
與一般的Socket編程一樣,服務器端需要在某個端口上開啟一個ServerSocket,以等待、接受客戶端的請求。
采用多線程技術,支持多用戶同時訪問,對于每一個請求,都用一個線程專門去處理。
客戶端發送給服務器端的HTTP請求遵循一定的格式,服務器端需要根據HTTP請求確定請求的類型以及請求的文件名,這些信息都存儲在請求消息的第一行中。比如,用戶瀏覽器地址欄中輸入:"
http://localhost:80/test/hehe.htm
",那么產生的請求的第一行便是"GET/test/hehe.htm HTTP/1.1"
Socket的getInetAddress方法能獲得客戶端的網絡地址信息,包括IP和端口號。
在給客戶端發送響應消息時,也要按照HTTP協議,給響應消息添加頭信息,然后將被請求文件的字節數組添加到頭信息的后面,頭信息的第一行為為"HTTP/1.1 200 0K" 表示"HTTP協議的版本為1.1,處理請求成功",頭信息的第一行為"HTTP/1.1 400"表示"HTTP協議的版本為1.1,處理請求失敗,文件沒找到"。
/** */
/**
* HTTP的服務器,接收來自客戶端的HTTP請求。
* 將要發布的HTML文件放置在工程的根目錄下,
* 然后在瀏覽器中輸入類似"
http://localhost
:80/"的網址,
* 將能夠顯示網頁的內容。
*/
public
class
HttpServer
{
//
服務器名和端口
String serverName;
int
serverPort;
//
定義server的名字、版本號、端口
public
HttpServer(String name,
int
port)
{
this
.serverName
=
name;
this
.serverPort
=
port;
}
public
void
run()
{
//
顯示名字和端口號
System.out.println(
"
HttpServer:
"
+
serverName
+
"
:
"
+
serverPort);
try
{
//
得到服務器監聽端口
ServerSocket server
=
new
ServerSocket(serverPort);
do
{
//
等待連接請求
Socket client
=
server.accept();
//
為連接請求分配一個線程
(
new
HTTPServerThread(client)).start();
}
while
(
true
);
}
catch
(Exception e)
{
e.printStackTrace();
System.exit(
1
);
}
}
//
構造一個server,并運行
public
static
void
main(String args[])
{
HttpServer server
=
new
HttpServer(
"
MyHTTPServer
"
,
80
);
server.run();
}
}
/** */
/**
* 處理HTTP請求的線程,一個HTTP請求對應一個線程
*/
class
HTTPServerThread
extends
Thread
{
//
服務器與客戶端之間的socket
Socket client;
public
HTTPServerThread(Socket client)
{
this
.client
=
client;
}
public
void
run()
{
try
{
//
顯示連接信息
describeConnectionInfo(client);
//
獲取流向到客戶端的輸出流
BufferedOutputStream outStream
=
new
BufferedOutputStream(client
.getOutputStream());
//
獲取來自客戶端的輸入流
HTTPInputStream inStream
=
new
HTTPInputStream(client
.getInputStream());
//
得到客戶端的請求頭(自定義類)
HTTPRequest request
=
inStream.getRequest();
//
顯示頭信息
request.log();
//
目前只處理GET請求
if
(request.isGetRequest())
{
processGetRequest(request, outStream);
}
System.out.println(
"
Request completed. Closing connection.
"
);
//
關閉socket
client.close();
}
catch
(IOException e)
{
System.out.println(
"
IOException occurred .
"
);
e.printStackTrace();
}
}
//
顯示socket連接信息
void
describeConnectionInfo(Socket client)
{
//
客戶端的主機名
String destName
=
client.getInetAddress().getHostName();
//
客戶端的IP地址
String destAddr
=
client.getInetAddress().getHostAddress();
//
客戶端的端口
int
destPort
=
client.getPort();
//
打印信息,表示客戶端已經連接到本服務器上
System.out.println(
"
Accepted connection to
"
+
destName
+
"
(
"
+
destAddr
+
"
)
"
+
"
on port
"
+
destPort
+
"
.
"
);
}
//
處理GET請求
void
processGetRequest(HTTPRequest request, BufferedOutputStream outStream)
throws
IOException
{
//
獲得客戶端要get的文件名
String fileName
=
request.getFileName();
File file
=
new
File(fileName);
//
如果文件存在,則將文件內容發送到socket的輸出流,即客戶端。
if
(file.exists())
{
sendFile(outStream, file);
}
else
{
System.out.println(
"
File
"
+
file.getCanonicalPath()
+
"
does not exist.
"
);
}
}
//
發送文件內容到客戶端,這里以HTTP 1.1的協議實現的
void
sendFile(BufferedOutputStream out, File file)
{
try
{
//
將文件內容全部讀入到一個字節數組中
DataInputStream in
=
new
DataInputStream(
new
FileInputStream(file));
int
len
=
(
int
) file.length();
byte
buffer[]
=
new
byte
[len];
//
完全讀取,然后關閉文件流
in.readFully(buffer);
in.close();
//
寫到socket的輸出流中
out.write(
"
HTTP/1.1 200 OK\r\n
"
.getBytes());
out.write((
"
Content-Length:
"
+
buffer.length
+
"
\r\n
"
).getBytes());
out.write(
"
Content-Type: text/HTML\r\n\r\n
"
.getBytes());
out.write(buffer);
out.flush();
out.close();
//
寫文件內容結束,log信息
System.out.println(
"
File sent:
"
+
file.getCanonicalPath());
System.out.println(
"
Number of bytes:
"
+
len);
}
catch
(Exception e)
{
try
{
//
發送失敗
out.write((
"
HTTP/1.1 400
"
+
"
No can do
"
+
"
\r\n
"
).getBytes());
out.write(
"
Content-Type: text/HTML\r\n\r\n
"
.getBytes());
}
catch
(IOException ioe)
{
}
System.out.println(
"
Error retrieving
"
+
file);
}
}
}
/** */
/**
* 實現讀客戶端請求的幫助類
*/
class
HTTPInputStream
extends
FilterInputStream
{
public
HTTPInputStream(InputStream in)
{
super
(in);
}
//
讀一行,當輸入流中沒有數據,或者讀到"\r\n"時,一行結束。
public
String readLine()
throws
IOException
{
StringBuffer result
=
new
StringBuffer();
boolean
finished
=
false
;
//
'\r'為回車符,值為13,'\n'為換行符,值為10
//
cr變量表示是否已經讀到換行符
boolean
cr
=
false
;
do
{
int
ch
=
-
1
;
//
讀一個字節
ch
=
read();
if
(ch
==
-
1
)
{
return
result.toString();
}
result.append((
char
) ch);
//
去掉最后的'\r\n'
if
(cr
&&
(ch
==
10
))
{
result.setLength(result.length()
-
2
);
return
result.toString();
}
//
讀到回車符,設置標識
if
(ch
==
13
)
{
cr
=
true
;
}
else
{
cr
=
false
;
}
}
while
(
!
finished);
return
result.toString();
}
//
得到所有的請求
public
HTTPRequest getRequest()
throws
IOException
{
HTTPRequest request
=
new
HTTPRequest();
String line;
do
{
//
依次讀取
line
=
readLine();
//
將請求填入容器
if
(line.length()
>
0
)
{
request.addLine(line);
}
else
{
break
;
}
}
while
(
true
);
//
返回
return
request;
}
}
//
客戶端請求的封裝類
class
HTTPRequest
{
//
請求的數據,按行存儲
Vector lines
=
new
Vector();
public
HTTPRequest()
{
}
public
void
addLine(String line)
{
lines.addElement(line);
}
//
判斷是否是Get請求
boolean
isGetRequest()
{
if
(lines.size()
>
0
)
{
//
獲取請求內容的第一行,如果頭三個字符是"GET",則為Get請求
String firstLine
=
(String) lines.elementAt(
0
);
if
(firstLine.length()
>
0
)
{
if
(firstLine.substring(
0
,
3
).equalsIgnoreCase(
"
GET
"
))
{
return
true
;
}
}
}
return
false
;
}
//
從請求中解析到文件名
//
一般第一行的消息如此類格式:"GET /hehe.htm HTTP/1.1"
/** */
/**
* 從請求中解析到文件名,只需要處理第一行即可。
* 第一行的格式有如下幾種:
* (1)如果請求的URL為"
http://localhost
:80/test/hehe.htm",
* 則第一行的內容為"GET /test/hehe.htm HTTP/1.1"。
* (2)如果請求的URL為"
http://localhost
:80",
* 則第一行的內容為"GET HTTP/1.1",此時應該找默認的html文件,如index.htm
* (3)如果請求的URL為"
http://localhost
:80/test",
* 則第一行的內容為"GET /test/ HTTP/1.1",此時應該找test目錄下默認的html文件
*/
String getFileName()
{
if
(lines.size()
>
0
)
{
//
得到vector中第一個元素
String firstLine
=
(String) lines.elementAt(
0
);
System.out.println(
"
firstLine:
"
+
firstLine);
//
根據http消息格式得到文件名
String fileName
=
firstLine.substring(firstLine.indexOf(
"
"
)
+
1
);
int
n
=
fileName.indexOf(
"
"
);
//
URL在兩個空格之間
if
(n
!=
-
1
)
{
fileName
=
fileName.substring(
0
, n);
}
//
去掉第一個'/'
try
{
if
(fileName.charAt(
0
)
==
'
/
'
)
{
fileName
=
fileName.substring(
1
);
}
}
catch
(StringIndexOutOfBoundsException ex)
{
}
//
默認首頁,這里認為index.htm為默認的首頁
//
類似于'
http://localhost
:80'的情況
if
(fileName.equals(
""
))
{
fileName
=
"
index.htm
"
;
}
//
類似于'
http://localhost
:80/download/'的情況
if
(fileName.charAt(fileName.length()
-
1
)
==
'
/
'
)
{
fileName
+=
"
index.htm
"
;
}
System.out.println(
"
fileName:
"
+
fileName);
return
fileName;
}
else
{
return
""
;
}
}
//
顯示請求信息
void
log()
{
System.out.println(
"
Received the following request:
"
);
for
(
int
i
=
0
; i
<
lines.size();
++
i)
{
System.out.println((String) lines.elementAt(i));
}
}
}
--
學海無涯
Powered by:
BlogJava
Copyright © 啥都寫點
主站蜘蛛池模板:
股票
|
连江县
|
墨竹工卡县
|
海晏县
|
兰西县
|
绥中县
|
锦州市
|
邹城市
|
巴彦县
|
吕梁市
|
怀来县
|
嘉祥县
|
叙永县
|
家居
|
洪江市
|
宁明县
|
榕江县
|
琼海市
|
叙永县
|
高州市
|
赫章县
|
腾冲县
|
榕江县
|
淮阳县
|
宜兴市
|
康平县
|
桓仁
|
海淀区
|
博湖县
|
靖边县
|
平武县
|
宁陵县
|
沙雅县
|
湄潭县
|
三河市
|
开平市
|
淳化县
|
长兴县
|
五华县
|
荔波县
|
巴马
|