程序有点BUG,欢迎高手指点,为啥不同的浏览器差别这么大?
运行服务器端程序后,在浏览器分别输入如下请求路径观察效果(我的服务器资源默认路径设置的是F:/project目录)。
http://localhost
http://localhost/myfile.txt
/*
* 模拟一个HTTP服务器的实现
* 客户端(浏览器)请求服务器的文件,服务器端程序接受连接并处理,将相应的数据写入socket,发送给客户端
* 本Web服务器将入站连接放入池中,由一个RequestProcessor类实例从池中移走连接并进行处理
*/
import java.io.*;
import java.net.*;
public class JHTTP extends Thread{
private File documentRootDirectory;
private String indexFileName="index.html";
private ServerSocket server;
private int numThreads =50;//设置服务器启动的线程数
public JHTTP(File documentRootDirectory,int port,String indexFileName) throws IOException{
if(!documentRootDirectory.isDirectory()){
throw new IOException(documentRootDirectory+" does not exist as a directory");
}
this.documentRootDirectory=documentRootDirectory;
this.indexFileName=indexFileName;
this.server=new ServerSocket(port);
}
public JHTTP(File documentRootDirectory,int port) throws IOException{
this(documentRootDirectory,port,"index.html");
}
public JHTTP(File documentRootDirectory) throws IOException{
this(documentRootDirectory,80,"index.html");
}
public void run(){
//开启处理请求的线程,该线程会从socket池中取出一个socket连接,进行数据传输
for(int i=0;i
Thread t=new Thread(new RequestProcessor(documentRootDirectory, indexFileName));
t.start();
}
System.out.println("Accepting connections on port "+server.getLocalPort()+"...");
System.out.println("Document Root:"+documentRootDirectory);
//服务器不停地接受请求
while(true){
try {
Socket connection=server.accept();
RequestProcessor.processRequest(connection);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
File docRoot;//得到文档根
docRoot=new File("F:\\project");
//设置服务器的监听端口
int port;
port=80;
try {
JHTTP webServer=new JHTTP(docRoot,port);
webServer.start();
} catch (IOException e) {
System.out.println("Server could not start because of an "+e.getClass());
System.out.println(e);
}
}
}
//具体处理连接的线程类
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import java.io.*;
import java.net.Socket;
public class RequestProcessor implements Runnable {
private static List pool = new LinkedList();
private File documentRootDirectory;
private String indexFileName = "index.html";
public RequestProcessor(File documentRootDirectory, String indexFileName) {
if (documentRootDirectory.isFile()) {
throw new IllegalArgumentException(
"documentRootDirectory must be a directory,not a file");
}
this.documentRootDirectory = documentRootDirectory;
// 返回此抽象路径名的规范形式
try {
this.documentRootDirectory = documentRootDirectory
.getCanonicalFile();
} catch (IOException e) {
System.out.println(e);
}
if (indexFileName != null) {
this.indexFileName = indexFileName;
}
}
public static void processRequest(Socket request) {
// 将对应于每一个客户端的socket连接放入池中,通知线程来处理他们
synchronized (pool) {
pool.add(pool.size(), request);
pool.notifyAll();
}
}
@Override
public void run() {
// 执行安全性检查,请求的文档不能超过根目录
String root = documentRootDirectory.getPath();
// 由于采用线程池的策略,所以说线程要不停地执行,以处理客户端的请求池(socket池)中的连接
while (true) {
Socket connection;
synchronized (pool) {
while (pool.isEmpty()) {
try {
pool.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
connection = (Socket) pool.remove(0);
}
// 通过socket这个中介进行服务器客户端的数据交换
try {
OutputStream raw;
raw = new BufferedOutputStream(connection.getOutputStream());
Writer out = new OutputStreamWriter(raw);
Reader in = new InputStreamReader(new BufferedInputStream(
connection.getInputStream()), "ASCII");
// 存储客户端请求的第一行数据
StringBuffer requestLine = new StringBuffer();
int c;
while (true) {
c = in.read();
if (c == '\r' || c == '\n')
break;
requestLine.append((char) c);
}
String get = requestLine.toString();
System.out.println(get);// 记录请求的头一行(要对头行进行一些分解,如下)
StringTokenizer st = new StringTokenizer(get);
String method = st.nextToken();
String version = "";
// 本案例目前只处理GET请求
String filename;
String contentType;
if (method.equals("GET")) {
filename = st.nextToken();
if (filename.endsWith("/"))
filename += indexFileName;
contentType = guessContentTypeFromName(filename);
if (st.hasMoreTokens()) {
version = st.nextToken();
}
File theFile = new File(documentRootDirectory,
filename.substring(1, filename.length()));
if (theFile.canRead()
&& theFile.getCanonicalPath().startsWith(root)) {
DataInputStream fis = new DataInputStream(
new BufferedInputStream(new FileInputStream(
theFile)));
byte[] theData = new byte[(int) theFile.length()];
fis.readFully(theData);
fis.close();
if (version.startsWith("HTTP ")) {// 发送MIME首部
out.write("HTTP/1.0 200 OK\r\n");// HTTP协议规定的头格式,就是要求回车换行,就必须是\r\n
Date now = new Date();
out.write("Date:" + now + "\r\n");
out.write("Server:JHTTP/1.0\r\n");
out.write("Content-Length:" + theData.length
+ "\r\n");
out.write("Content-Type:" + contentType
+ "\r\n\r\n");
out.flush();// 切记结束的时候要刷新,写入缓冲区剩余数据
}
// 发送实际请求的文件(可能是图片或其它二进制文件)
raw.write(theData);
raw.flush();
} else {// 无法找到文件
if (version.startsWith("HTTP ")) {// 发送MIME首部
out.write("HTTP/1.0 404 File Not Found ON MyServer\r\n");// HTTP协议规定的头格式,就是要求回车换行,就必须是\r\n
Date now = new Date();
out.write("Date:" + now + "\r\n");
out.write("Server:JHTTP/1.0\r\n");
out.write("Content-Type:text/html\r\n\r\n");
}
out.write("\r\n");
out.write("
File not found\r\n");out.write("\r\n");
out.write("
");out.write("
HTTP Error 404:File not found\r\n");
out.write("\r\n");
out.flush();
}
} else {// 不是'GET'方法
if (version.startsWith("HTTP ")) {// 发送MIME首部
out.write("HTTP/1.0 501 Not Implemented\r\n");// HTTP协议规定的头格式,就是要求回车换行,就必须是\r\n
Date now = new Date();
out.write("Date:" + now + "\r\n");
out.write("Server:JHTTP/1.0\r\n");
out.write("Content-Type:text/html\r\n\r\n");
}
out.write("\r\n");
out.write("
Not Implemented\r\n");out.write("\r\n");
out.write("
");out.write("
HTTP Error 501:Not Implemented\r\n");
out.write("\r\n");
out.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
connection.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static String guessContentTypeFromName(String name) {
if (name.endsWith(".htm") || name.endsWith(".html")) {
return "text/html";
} else if (name.endsWith(".txt") || name.endsWith(".java")) {
return "text/plain";
} else if (name.endsWith(".class")) {
return "application/octet-stream";
} else if (name.endsWith(".gif")) {
return "image/gif";
} else if (name.endsWith(".jpg") || name.endsWith(".jpeg")) {
return "image/jpeg";
} else if (name.endsWith(".mp3")) {
return "audio/mpeg";
} else {
return "text/plain";
}
}
}