一个基于java的web服务器使用这两个重要的类:java.net.Socket和java.net.ServerSocket,并通过HTTP消息进行通信。在实现Web服务器之前有必要简要说明一下超文本传输协议(HTTP)。
超文本传输协议(HTTP)
http是一种无状态的请求和相应协议,请大家暂时记住无状态这一概念,在后续介绍session时将会向大家阐述有状态和无状态的区别。在HTTP中,始终由客户端发送HTTP请求。web服务器从不主动联系客户端或对客户端做回调连接,服务器端只根据客户端发来的请求做出响应。下面将介绍HTTP请求和HTTP响应和Socket类
HTTP请求
一个HTTP请求包括三个组成部分:
1.方法—统一资源标示符(URI)—协议/版本
2.请求的头部
3.主体内容
示例如下:
[plain] view plaincopy
POST /examples/default.jsp HTTP/1.1
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: localhost
User-Agent: Mozilla/4.0
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
lastName=Franks&firstName=Michael
HTTP响应
类似于HTTP请求,一个HTTP响应也包括三个组成部分:
1.方法-统一资源标示符(URI)-协议/版本
2.响应的头部
3.主体内容
下面是一个HTTP响应的例子:
[plain] view plaincopy
HTTP/1.1 200 OK
Server: IBM/4.0
Date: Sat, 6 Nov 2013 13:13:00 GMT
Content-Type: text/html
Last-Modified: Sat, 5 Jan 2013 13:13:12 GMT
Content-Length: 112
Socket类
套接字是网络连接的一个端点。套接字使得一个应用可以从网络中读取和写入数据。放在两个不同的计算机上的两个应用可以通过连接发送和接受字节流。为了从你的应用发送一条信息到另一个应用,你需要指导另一个应用的IP地址和套接字端口。
ServerSocket类
Socket类代表一个客户端套接字,即任何时候你想连接到一个远程服务器应用的时候你构造的套接字。如果是一个服务器程序依靠Socket类是行不通的。你的服务器必须随时待命,因为客户端何时想你发送请求是不知道的。
[plain] view plaincopy
ServerSocket和Socket不同,服务器套接字的角色是等待来自客户端的连接请求。一旦服务器套接字获得一个连接请求,它创建一个Socket实例来与客户端进行通信。
下面我们来看看这三个类:
HttpServer类
[java] view plaincopy
package com.vipshop.test;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import com.vipshop.tomcat.pyrmont.Request;
import com.vipshop.tomcat.pyrmont.Response;
public class HttpServer {
public static final String WEB_ROOT = System.getProperty("user.dir")
+ File.separator + "webroot";
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
private boolean shutdown = false;
public static void main(String[] args) {
HttpServer server = new HttpServer();
server.await();
}
public void await() {
ServerSocket serverSocket = null;
int port = 8080;
try {
serverSocket = new ServerSocket(port, 1, InetAddress
.getByName("127.0.0.1"));
} catch (UnknownHostException e) {
e.printStackTrace();
} 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 revious URI is a shutdown command
shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
}
[java] view plaincopy
Request类
[java] view plaincopy
package com.vipshop.test;
import java.io.IOException;
import java.io.InputStream;
public class Request {
private InputStream input;
private String uri;
public Request(InputStream input) {
this.input = input;
}
public void parse() {
// Read a set of characters from the socket
StringBuffer request = new StringBuffer(2018);
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.println();
System.out.println("request.toString():");
System.out.print(request.toString());
System.out.println();
uri = parseUri(request.toString());
}
private String parseUri(String requestString) {
int index1, index2;
index1 = requestString.indexOf(' ');
if (index1 != -1) {
index2 = requestString.indexOf(' ', index1 + 1);
return requestString.substring(index1 + 1, index2);
}
return null;
}
public String getUri() {
return uri;
}
}
Response类
[java] view plaincopy
package com.vipshop.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
public class Response {
private static final int BUFFER_SIZE = 1024;
private Request request;
private OutputStream output;
public Response(OutputStream output) {
this.output = output;
}
public void setRequest(Request request) {
this.request = request;
}
public void sendStaticResource() throws IOException {
byte[] bytes = new byte[BUFFER_SIZE];
FileInputStream fis = null;
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 Fount\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: 23\r\n" +
"\r\n" +
"
File Not Found
";output.write(errorMessage.getBytes());
}
if (fis != null) {
fis.close();
}
}
}