http服务器主要由三个类构成:httpserver、request和response。其中程序的入口在httpserver类,它调用await()方法,使得server开始等候客户端的连接。当客户端连接后,它将把静态的页面内容发送给客户端浏览器。下面分别介绍这三个类:
1:httpserver类
httpserver需要有一个服务器的根目录这在web_root变量中定义的:
public static final string web_root =system.getproperty("user.dir") + file.separator + "webroot";当我们运行服务器的时候可以通过-d选项指定环境变量user.dir的值。这个类中最重要的方法就是await()方法,内容如下:
public void await() {
serversocket serversocket = null;
int port = 8080;
try {
serversocket = new serversocket(port, 1, inetaddress.getbyname("127.0.0.1"));
}
catch (ioexception e) {
e.printstacktrace();
system.exit(1);
}
// loop waiting for a request
while (!shutdown) {
socket socket = null;
inputstream input = null;
outputstream output = null;
try {
socket = serversocket.accept();
input = socket.getinputstream();
output = socket.getoutputstream();
// create request object and parse
request request = new request(input);
request.parse();
// create response object
response response = new response(output);
response.setrequest(request);
response.sendstaticresource();
// close the socket
socket.close();
//check if the previous uri is a shutdown command
shutdown = request.geturi().equals(shutdown_command);
}
catch (exception e) {
e.printstacktrace();
continue;
}
}
}
await()方法内构造一个serversocket的实例,等客户端连接进来的时候把socket.getinputstream()传递给request类进行解析,把socket.getoutputstream()传递给response类,然后再把request对象传递给response,最后调用response.sendstaticresource()方法发送数据给客户端。socket.close()后监测是不是接受到了关闭server的命令,如果是的话跳出循环结束程序。
2. request类
request类的主要目的是对http请求进行封装,它有一个inputstream类型参数的构造器
public request(inputstream input) {
this.input = input;
}
同时它还有一个重要的string类型的成员变量uri,request的目的就是从inputstream中提取uri,这是由两个函数实现的
public void parse() {
// read a set of characters from the socket
stringbuffer request = new stringbuffer(2048);
int i;
byte[] buffer = new byte[2048];
try {
i = input.read(buffer);
}
catch (ioexception e) {
e.printstacktrace();
i = -1;
}
for (int j=0; j<i; j++) {
request.append((char) buffer[j]);
}
system.out.print(request.tostring());
uri = parseuri(request.tostring());
}
private string parseuri(string requeststring) {
int index1, index2;
index1 = requeststring.indexof(' ');
if (index1 != -1) {
index2 = requeststring.indexof(' ', index1 + 1);
if (index2 > index1)
return requeststring.substring(index1 + 1, index2);
}
return null;
}
其中parseuri(string request)方法是私有方法,它把string参数进行解析把两个空格之间的字符串返回,这是遵循http请求的定义规则的,如果你不清楚可以参考基于java实现http服务器之一。
2.response类
response的两个重要的成员变量分别是outputstream类型的output和requeset类型的request,这个类的功能就是从request的实例里面得到uri,然后和web_root进行相加得到文件所在的绝对路径,然后读取这个文件的内容把它写入到socket.getoutputstream()里面去。
public void sendstaticresource() throws ioexception {
byte[] bytes = new byte[buffer_size];
fileinputstream fis = null;
try {
file file = new file(httpserver.web_root, request.geturi());
if (file.exists()) {
fis = new fileinputstream(file);
int ch = fis.read(bytes, 0, buffer_size);
while (ch!=-1) {
output.write(bytes, 0, ch);
ch = fis.read(bytes, 0, buffer_size);
}
}
else {
// file not found
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) {
// thrown if cannot instantiate a file object
system.out.println(e.tostring() );
}
finally {
if (fis!=null)
fis.close();
}
}
下面说明如何运行这个应用程序,首先你下载源代码,把它解到你的d盘例如temp目录下,它包括三个目录src lib webroot其中webroot内有一个index.html文件供测试用。从command中运行
cd temp
javac -d . src/ex01/pyrmont/*.java
这样在当前目录(d:/temp)会出现ex01/pyrmont目录,里面是编译得到的class文件,接下来运行
java -duser.dir=d:/temp ex01.pyrmont.httpserver,-d选项可以设定系统环境变量
然后从浏览器输入http://localhost:8080/index.html,这样你就可以看到server发送给你的静态页面index.html了。
闽公网安备 35060202000074号