任务:
以JDK为开发工具,利用 Socket通信机制实现一个多线程的WEB服务器,该服务器具有以下功能:
1.能够并行服务于多个请求。
2.对于每个请求,显示接收到的HTTP请求报文的内容,并产生适当的响应(若找到用户请求对象,则返回该对象。否则发送一个包含适当提示信息的响应消息,从而可以在浏览器窗口中显示差错信息。)
代码:
import java.io.* ;
import java.net.* ;
import java.util.StringTokenizer;
final class HttpRequest implements Runnable {
final static String CRLF = "\r\n";
final static Boolean DEBUG = false;
InetAddress clientIP;
int clientPort;
Socket socket;
/*
public HttpRequest(Socket socket, InetAddress clientIP, int clientPort) {
this.socket = socket;
this.clientIP = clientIP;
this.clientPort = clientPort;
}
*/
public HttpRequest(Socket socket) {
this.socket = socket;
this.clientIP = socket.getInetAddress();
clientPort = socket.getPort();
}
public void run() {
try {
processRequest();
} catch (Exception e) {
System.out.println(e);
}
}
private void processRequest() throws Exception {
InputStreamReader is=new InputStreamReader(this.socket.getInputStream());
BufferedReader br = new BufferedReader(is);
DataOutputStream os = new DataOutputStream(this.socket.getOutputStream());
String requestLine = br.readLine();
StringTokenizer tokens = new StringTokenizer(requestLine);
String method = tokens.nextToken().toUpperCase();
if (method.contentEquals("GET")) {
String fileName = tokens.nextToken();
if (fileName.startsWith("/"))
fileName = "." + fileName;
if (DEBUG) {
System.out.println("到达了一个Request消息!");
System.out.println("客户:IP:" + (clientIP.toString()).substring(1) + "Port:" + clientPort);
String headLine;
while (((headLine = br.readLine()).length()) != 0) {
System.out.println(headLine);
}
}
FileInputStream fis = null;
boolean fileExists;
try {
fis = new FileInputStream(fileName);
fileExists = true;
} catch (FileNotFoundException e) {
fileExists = false;
}
String statusLine;
String contentTypeLine;
String contentLength;
String entityBody = null;
/*
if (fileExists) {
statusLine = "HTTP/1.0 200 OK" + CRLF;
contentLength = "Content-Length:" + fis.available() + CRLF;
contentTypeLine = "Content-Type:" + contentType(fileName) + CRLF + CRLF;
}
else {
statusLine = "HTTP/1.0 200 OK" + CRLF;
contentLength = "Content-Length:113" + CRLF;
contentTypeLine = "Content-Type:text/htm;" + CRLF + CRLF;
entityBody = "<html>" + "<head>" + "<title>404 not found</title>" + "</head>" +
"<body>The object you requested is not server!</body>" + "</html>";
}
os.writeBytes(statusLine);
os.writeBytes(contentLength);
os.writeBytes(contentTypeLine);
*/
if (fileExists) {
statusLine="HTTP/1.1 200 OK"+CRLF;
contentTypeLine = "Content-type: " + contentType( fileName ) + CRLF;
} else {
statusLine="HTTP/1.1 404 NotFound"+CRLF;
contentTypeLine = "Content-type: text/html"+CRLF;
entityBody ="<html><title>Not found</title><h1>404 NotFound</h1></html>";
}
os.writeBytes(statusLine);
os.writeBytes(contentTypeLine);
os.writeBytes(CRLF);
if (fileExists) {
sendBytes(fis, os);
fis.close();
} else {
os.writeBytes(entityBody);
}
} else {
System.out.println("The method supported by the web server is GET only");
}
os.close();
br.close();
this.socket.close();
}
private static void sendBytes(FileInputStream fis, OutputStream os) throws Exception {
byte[] buffer = new byte[1024];
int bytes;
while ((bytes = fis.read(buffer)) != -1) {
os.write(buffer, 0, bytes);
}
}
private static String contentType(String fileName) {
if (fileName.endsWith(".htm") || fileName.endsWith(".html")) {
return "text/html";
}
if (fileName.endsWith(".java") || fileName.endsWith(".cc") || fileName.endsWith(".c")) {
return "text/plain";
}
if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".jpe")) {
return "image/jpeg";
}
if (fileName.endsWith(".doc")) {
return "application/msword";
}
if (fileName.endsWith(".docx")) {
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
}
if (fileName.endsWith(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (fileName.endsWith(".xls")) {
return "application/vnd.ms-excel";
}
return "text/plain";
}
}
import java.net.* ;
public final class MultiThreadedWebServer {
public static void main(String[] args) throws Exception {
int port = 8080;
/*
if (args.length < 1) {
System.out.println("启动服务器时必须指定Server的工作端口!格式:MultiThreadedWebServer XXXX");
} else {
port = Integer.parseInt(args[0]);
}
*/
ServerSocket socket = new ServerSocket(port);
System.out.println("The Web Server is ready for you! Its working port is " + port);
while (true) {
Socket connection = socket.accept();
HttpRequest request = new HttpRequest(connection);
Thread thread = new Thread(request);
thread.start();
}
}
}
运行效果:
需要注意:
博主一开始将准备好的文件(.jpg,.txt, .java等)放入src文件夹中会出现在浏览器找不到相关文件的情况,在放入上一级文件夹并且将out/production中产生的文件删除才得以显示。还要注意参考HTTP Response消息Content-Type头部规范。