Cyh的博客
Email:kissyan4916@163.com
posts - 26, comments - 19, trackbacks - 0, articles - 220
导航
BlogJava
首页
新随笔
联系
聚合
管理
公告
一直努力努力努力,像奴隶奴隶奴隶!~~
<
2024年12月
>
日
一
二
三
四
五
六
24
25
26
27
28
29
30
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
31
1
2
3
4
常用链接
我的随笔
我的文章
我的评论
我的参与
最新评论
随笔档案
(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标签的使用(18226)
2. struts2异常拦截器(5857)
3. struts2迭代标签(3845)
4. 用freemind 秒杀Spring Security(1914)
5. 加载顺序会影响对spring bean 的调用。(1489)
网络编程>>HTTP服务器
Posted on 2009-12-12 16:22
啥都写点
阅读(322)
评论(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 © 啥都写点