一个简单的web服务器例子
一个简单的web容器小例子,功能十分简单,只能访问静态资源,对于新手来说还是有一定的意义。主要分三个类
1、server类:主要功能开启socketServer,阻塞server,接收socket访问,解析request,创建request,作出响应
public class TestServer1 {
private boolean shutdown = false;
// web目录webroot
public static final String WEB_ROOT = System.getProperty("user.dir")
+ File.separator + "WebRoot";
public static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
public static void main(String[] args) {
TestServer1 server = new TestServer1();
server.await();
}
public void await() {
// 第一步、创建出serverSocket监听本机8080端口
ServerSocket server = null;
int port = 8080;
try {
server = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
} catch (Exception e) {
e.printStackTrace();
}
// 第二步、轮询阻塞住socketServer
while(!shutdown) {
Socket socket = null;
InputStream input = null;
OutputStream output = null;
try {
socket = server.accept();
input = socket.getInputStream();
output = socket.getOutputStream();
// 第三步、创建出request,解析request请求
Request req = new Request(input);
req.parseRequest();
// 第四步、创建response
Response response = new Response(output);
response.setRequest(req);
// 第五步、发送简单静态资源,关闭socket结束本次会话
response.sendStaticRes();
socket.close();
// 关闭指令
shutdown = req.getUri().equals(SHUTDOWN_COMMAND);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
当然了上面的是最简单的实现,也不能实现多线程,实际上的web容器肯定会创建一个线程池来接收请求
2、request 主要的工作解析input流,封装成request
class Request {
private InputStream input;
private String uri;
public Request(InputStream input) {
this.input = input;
}
/**
* 解析request请求内容
* GET /index.html HTTP/1.1
* Accept: text/html, application/xhtml+xml, *//*
* Accept-Language: zh-CN
* User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; MALCJS; rv:11.0) like Gecko
* Accept-Encoding: gzip, deflate
* Host: localhost:8080
* DNT: 1
* Connection: Keep-Alive
* Cookie: 这个地方应该如果有cookie,如果有session还有jsessionId的
*/
public void parseRequest() {
// 为什么只获取2048个字符,这是因为request请求内容的长度,出于安全或者其他方面的考虑,在浏览器端和服务器端都会做这么一个限制。
StringBuffer buffer = new StringBuffer(2048);
byte[] bytes = new byte[2048];
int i;
try {
i = input.read(bytes);
} catch (IOException e) {
e.printStackTrace();
i=-1;
}
for(int k=0; k<i; k++) {
buffer.append((char)bytes[k]);
}
System.out.println(buffer.toString());
uri = parseUri(buffer.toString());
}
/**
* GET /index.html HTTP/1.1 uri的位置
* @param reqStr
* @return
*/
private String parseUri(String reqStr) {
int index1, index2;
index1 = reqStr.indexOf(' ');
if (index1 != -1) {
index2 = reqStr.indexOf(' ', index1 + 1);
if (index2 > index1)
return reqStr.substring(index1 + 1, index2);
}
return null;
}
public String getUri() {
return uri;
}
}
解析成的http请求的具体内容,作为web开发人员应该要熟悉每个字段的意义,这个请求是浏览器本身按照http协议封装的一个请求,能够手写出这个请求当然更好。
3、response 通过request的uri找到对应的资源对请求作出响应,实际的情况肯定是有静态和动态资源例如servlet\filter等等,但是这里只是做了简单的静态的处理了
class Response {
private OutputStream output;
private Request request;
public Response(OutputStream output) {
this.output = output;
}
public void setRequest(Request req) {
this.request = req;
}
/**
* 简单处理静态资源
* @throws IOException
*/
public void sendStaticRes() throws IOException {
FileInputStream fis = null;
try {
File staticFile = new File(TestServer1.WEB_ROOT, request.getUri());
if(staticFile.exists()) {
fis = new FileInputStream(staticFile);
int i = 0;
byte[] buf = new byte[1024];
// 流的对拷
i = fis.read(buf, 0, 1024);
while(i!=-1) {
output.write(buf, 0, i);
i = fis.read(buf, 0, 1024);
}
} else {
// file not found 404
String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: 23\r\n" +
"\r\n" +
"<h1>File Not Found</h1>";
output.write(errorMessage.getBytes());
}
} catch (Exception e) {
e.printStackTrace();
} finally{
if(fis!=null)
fis.close();
fis = null;
}
}
}
同样响应内容你也应该要熟悉哪些组成部分
HTTP/1.1 200 OK //响应行 Date: Sat, 31 Dec 2005 23:59:59 GMT Content-Type: text/html;charset=ISO-8859-1 Content-Length: 122 <html> <head> <title>Test</title> </head> <body> This my page </body> </html>
至此一个简单的web容器就写好了,能够访问webRoot目录下的静态资源。
可以通过浏览器访问,也可以通过telnet端进行访问。在cmd命令行下telnet localhost 8080,就会连接上socketServer,然后就会等待输入,自然我们输入对应的请求报文,回车响应内容就出现了。
以上原创文章出自老罗家的树博客地址:http://www.cnblogs.com/TimBing/