java实现的HTTP简易服务器

程序有点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";
		}
	}
}
时间: 2024-10-10 22:20:11

java实现的HTTP简易服务器的相关文章

Tornado写简易服务器

我们都知道在Web开发中,都需要服务器,比如Java Web开发的Tomcat,WebLogic,WebSphere,现在来看利 用Tornado Web Server框架如何写一个简易的Python服务器. 一般来说只需要实现get和post方法就可以了.以上次使用redis数据库的例子说明,数据库插入代码如下: import redis import datetime class Database: def __init__(self): self.host = 'localhost' se

java多线程文件上传服务器

描述: (1)jdk自带线程池见 JDK自带线程池配置 (2)此上传文件服务器中上传文件的后缀名通过第一段缓冲字符流传递,此缓冲字符流大小为1024,在文件接收端以1024接收.处理. 1.服务器代码如下(使用jdk自带线程池): 1 /** 2 * 服务器处理多线程问题 3 * 4 * 1.因为服务器是要很多人访问的,因此里面一定要用多线程来处理,不然只能一个人一个人的访问,那还叫Y啥服务器 5 * 6 * 2,拿上面这个文件上传的例子来说,它将每个连接它的用户封装到线程里面去,把用户要执行的

我用JAVA做了个简易图像相似度计算器

简单说两句: 笔主利用这个七夕前后两天的寂寞时光,用JAVA磨了一个简单的图像相似度计算小程序,就在刚才终于纠结完毕,输出了1.0版本,小小的满足了一下可怜的虚荣心..→_→ 原理是使用最简单最基础的感知哈希算法,算法原理戳这里,绝对比笔主讲的要好: http://www.ruanyifeng.com/blog/2011/07/principle_of_similar_image_search.html UI设计图: 实际运行效果图: 关键算法: 1 // 全流程 2 public static

将本地Java程序部署到linux服务器并执行

需求:将本地Java程序部署到linux服务器并执行,首先要将本地Java程序打成jar包,然后拷贝到服务器后运行java -jar xx.jar 问题:该程序本地运行正常,服务端运行报错找不到第三方包中的类 原因:本地打jar包时有错,未能正确引入第三方包 解决:本地通过fat jar插件来打包,方法如下 在Eclipse 下 java 应用程序打包 Mainfest.mf 格式 首先保证程序在Eclipse下的正常执行,然后方法如下: ( 写在最前面 做好的Eclipse打包 还是使用插件

python搭建简易服务器实例参考

有关python搭建简易服务器的方法. 需求分析: 省油宝用户数 已经破了6000,原有的静态报表 已经变得臃肿不堪, 每次打开都要缓上半天,甚至浏览器直接挂掉 采用python搭建一个最最简易的 web 服务 请求一个nick 就返回 对应的 报表数据 参数用GET方式传送 调研与实现: 园里没找到靠谱的,google了半天,最终还是成功了. 以下是源码,里面记录了 其中的 一些问题 复制代码 代码如下: #! /usr/bin/env python # -*- coding: utf-8 -

windows7搭建ftp服务器与Java上传下载ftp服务器文件

1.Windows7搭建FTP服务器 1.1 首先新建一个用户,用于登录FTP进行操作,步骤:开始\控制面板\用户帐户和家庭安全\用户帐户\管理帐户\新建账户 1.2创建用户完成后我们开始添加IIS程序服务;进入控制面板\程序\打开或关闭Windows功能 然后点击打开在FTP服务器前面打勾,也就是把其子菜单的FTP服务和FTP扩展性打勾 1.3 创建FTP站点:进入控制面板\选择管理工具\信息服务管理器\添加站点 界面 下一步 下一步 1.4 查看FTP是否部署成功 完成FTP服务器的搭建.

java swing开发最简易计算器源代码

原文:java swing开发最简易计算器源代码 源代码下载地址:http://www.zuidaima.com/share/1550463496948736.htm 用java swing写的简易计算器 /** *@author www.zuidaima.com */ package com.zuidaima.swing; import java.awt.BorderLayout; import java.awt.EventQueue; import javax.swing.JFrame; i

JAVA 实现 简单的 HTTP服务器

关于JAVA的HTTP服务器的简单实现,还望大家给出宝贵建议,谢谢. 1.首先来说下HTTP所有的状态碼,相信对于网页开发的博友们,肯定不陌生. 状态码 状态码英文名称 中文描述 100 Continue 继续.客户端应继续其请求 101 Switching Protocols 切换协议.服务器根据客户端的请求切换协议.只能切换到更高级的协议,例如,切换到HTTP的新版本协议 200 OK 请求成功.一般用于GET与POST请求 201 Created 已创建.成功请求并创建了新的资源 202

C#调用Java的WebService出现500 服务器错误

最近在用C#调用Java写的WebService时,发现老是返回500 服务器错误,到底什么原因一直找不出来, 后来google了以后,找到国外的http://stackoverflow.com站点已经有人碰到过这个问题了. 转帖如下: HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest; WebResponse wr = req.GetResponse(); When the server returns 500 Inte