码迷,mamicode.com
首页 > 编程语言 > 详细

java实现的HTTP简易服务器

时间:2014-12-30 19:08:01      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:

程序有点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<numThreads;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("<HTML>\r\n");
						out.write("<HEAD><TITLE>File not found</TITLE>\r\n");
						out.write("</HEAD>\r\n");
						out.write("<BODY>");
						out.write("<H1>HTTP Error 404:File not found\r\n");
						out.write("</BODY></HTML>\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("<HTML>\r\n");
					out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n");
					out.write("</HEAD>\r\n");
					out.write("<BODY>");
					out.write("<H1>HTTP Error 501:Not Implemented\r\n");
					out.write("</BODY></HTML>\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";
		}
	}
}



java实现的HTTP简易服务器

标签:

原文地址:http://blog.csdn.net/hellozpc/article/details/42268913

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!