HTTPf服务器(3)
功能完整的HTTP服务器
导语
这个一个功能完备的HTTP服务器。它可以提供一个完整的文档输,包括图像,applet,HTML文件,文本文件。它与SingleFileHttpServer非常相似,只不过它所关注的是GET请求的内容。它会根据GET请求的内容在自己的工作目录查找对应的资源,并将该资源返回给用户。这个服务是相当轻量级的。
主线程代码
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
public class JHTTP {
	//开启日志
	private static final Logger logger = Logger.getLogger(JHTTP.class.getCanonicalName());
	//线程数
	private static final int NUM_THREAD = 50;
	//默认主页
	private static final String INDEX_FILE = "index.html";
	//服务器工作目录
	private final File rootDirectory;
	//端口号
	private final int port;
	/**
	 *
	 * @param _rootDirectory 工作目录
	 * @param _port	端口号
	 */
	public JHTTP(File _rootDirectory, int _port) {
		if (!_rootDirectory.isDirectory())
				throw new RuntimeException(_rootDirectory + "does not exist as a directory");
		rootDirectory = _rootDirectory;
		port = _port;
	}
	/**
	 * 启动服务器
	 * @throws IOException
	 */
	public void start() throws IOException {
		ExecutorService pool = Executors.newFixedThreadPool(NUM_THREAD);
		try (ServerSocket server = new ServerSocket(port)) {
			logger.info("Accepting connection on port" + server.getLocalPort());
			logger.info("Document Root: " + rootDirectory);
			while (true) {
				try {
					Socket request = server.accept();
					pool.execute(new RequestProcessor(rootDirectory, INDEX_FILE, request));
				} catch (IOException e) {
					logger.warning("Error accepting connection");
				}
			}
		}
	}
	public static void main(String[] args) {
		//设置工作目录
		File docroot;
		try {
			docroot = new File(args[0]);
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("Usage: java JHTTP docroot port");
			return;
		}
		//设置监听端口号
		int port;
		try {
			port = Integer.parseInt(args[1]);
			if (port < 0 || port > 65535) port = 8080;
		} catch (RuntimeException e) {
			port = 8080;
		}
		try {
			JHTTP webserver = new JHTTP(docroot, port);
			webserver.start();
		} catch (IOException e) {
			logger.severe("Server cloud not start");
		}
	}
}
主线程代码比较简单,默认监听8080端口,将连接提交给工作线程来处理。
处理线程
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;
import java.net.URLConnection;
import java.nio.file.Files;
import java.util.Date;
import java.util.logging.Logger;
public class RequestProcessor implements Runnable {
	private final static Logger logger = Logger.getLogger(RequestProcessor.class.getCanonicalName());
	private File rootDirectory;
	private String indexFileName = "index.html";
	private Socket conn;
	public RequestProcessor(File _rootDirectory, String _indexFileName,
			Socket _conn) {
		if (_rootDirectory.isFile())
			throw new IllegalArgumentException("rootDirectory muse be a directory, not a file");
		rootDirectory = _rootDirectory;
		indexFileName = _indexFileName;
		conn = _conn;
	}
	@Override
	public void run() {
		String root = rootDirectory.getPath();
		try {
			BufferedOutputStream raw = new BufferedOutputStream(conn.getOutputStream());
			Writer out = new BufferedWriter(new OutputStreamWriter(raw, "utf-8"));
			BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			String get = in.readLine();
			if (get != null) {
				logger.info(conn.getRemoteSocketAddress() + " " + get);
				String[] pieces = get.split("\\s+");
				String method = pieces[0];
				String version = "";
				if (method.equals("GET")) {
					String fileName = pieces[1];
					if (fileName.endsWith("/")) fileName += indexFileName;
					String contentType = URLConnection.getFileNameMap().getContentTypeFor(root +fileName);
					if (pieces.length > 2) {
						version = pieces[2];
					}
					File theFile = new File(rootDirectory, fileName.substring(1, fileName.length()));
					if (theFile.canRead() && theFile.getCanonicalPath().startsWith(root)) {
						byte[] theData = Files.readAllBytes(theFile.toPath());
						if (version.startsWith("HTTP/"))
							sendHeader(out, "HTTP/1.1 200 OK", contentType, theData.length);
						raw.write(theData);
						raw.flush();
						raw.close();
					} else { //无法找到文件
						String body = "<html><head><title>File not found</title></head><body>Error 404:文件未找到</body></html>";
						if (version.startsWith("HTTP/"))
							sendHeader(out, "HTTP/1.1 4O4 File Not Found", "text/html;charset=utf-8", body.getBytes("utf-8").length);
						out.write(body);
						out.flush();
						out.close();
					}
				} else {
					String body = "<html><head><title>File not found</title></head><body>Error 501:无法处理该请求</body></html>";
					if (version.startsWith("HTTP/"))
						sendHeader(out, "HTTP/1.1 5O1 Not Implemented", "text/html;charset=utf-8", body.getBytes("utf-8").length);
					out.write(body);
					out.flush();
					out.close();
				}
			}
		} catch (IOException e){
			logger.warning("Error talking to " + conn.getRemoteSocketAddress());
		} finally {
			try {
				conn.close();
			} catch (IOException e) {}
		}
	}
	private void sendHeader(Writer out, String responseCode, String contentType, int length) throws IOException {
		out.write(responseCode + "\r\n");
		out.write("Date: " + new Date() + "\r\n");
		out.write("Server: JHTTP 2.0\r\n");
		out.write("Content-Type: " + contentType + "\r\n");
		out.write("Content-Length: " + length + "\r\n\r\n");
		out.flush();
	}
}
在处理线程中处理客户端的请求,通过解析GET请求的资源从本地中查找对应的资源。如果没有找的则返回404错误
HTTPf服务器(3)的更多相关文章
- Apache是目前应用最广的Web服务器,PHP3是一种类似ASP的脚本语言
		
一.如何获得软件? 获得这3个软件包的方法很多,目前大多数Linux分发都捆绑了这3个软件包,如RedHat.本文介绍的安装方法是基于从这些软件的官方站点上下载获得的软件包进行的,针对RedHat L ...
 - App开发:模拟服务器数据接口 - MockApi
		
为了方便app开发过程中,不受服务器接口的限制,便于客户端功能的快速测试,可以在客户端实现一个模拟服务器数据接口的MockApi模块.本篇文章就尝试为使用gradle的android项目设计实现Moc ...
 - 闰秒导致MySQL服务器的CPU sys过高
		
今天,有个哥们碰到一个问题,他有一个从库,只要是启动MySQL,CPU使用率就非常高,其中sys占比也比较高,具体可见下图. 注意:他的生产环境是物理机,单个CPU,4个Core. 于是,他抓取了CP ...
 - 闲来无聊,研究一下Web服务器 的源程序
		
web服务器是如何工作的 1989年的夏天,蒂姆.博纳斯-李开发了世界上第一个web服务器和web客户机.这个浏览器程序是一个简单的电话号码查询软件.最初的web服务器程序就是一个利用浏览器和web服 ...
 - SignalR系列续集[系列8:SignalR的性能监测与服务器的负载测试]
		
目录 SignalR系列目录 前言 也是好久没写博客了,近期确实很忙,嗯..几个项目..头要炸..今天忙里偷闲.继续我们的小系列.. 先谢谢大家的支持.. 我们来聊聊SignalR的性能监测与服务器的 ...
 - 使用 Nodejs 搭建简单的Web服务器
		
使用Nodejs搭建Web服务器是学习Node.js比较全面的入门教程,因为要完成一个简单的Web服务器,你需要学习Nodejs中几个比较重要的模块,比如:http协议模块.文件系统.url解析模块. ...
 - 通过ProGet搭建一个内部的Nuget服务器
		
.NET Core项目完全使用Nuget 管理组件之间的依赖关系,Nuget已经成为.NET 生态系统中不可或缺的一个组件,从项目角度,将项目中各种组件的引用统统交给NuGet,添加组件/删除组件/以 ...
 - 谈谈如何使用Netty开发实现高性能的RPC服务器
		
RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...
 - 游戏服务器菜鸟之C#初探一游戏服务
		
本人80后程序猿一枚,原来搞过C++/Java/C#,因为工作原因最后选择一直从事C#开发,因为读书时候对游戏一直比较感兴趣,机缘巧合公司做一个手游的项目,我就开始游戏服务器的折腾之旅. 游戏的构架是 ...
 
随机推荐
- spider RPC高级特性
			
多租户 spider原生支持多租户部署,spider报文头对外开放了机构号.系统号两个属性用于支持多租户场景下的路由. 多租户场景下的路由可以支持下述几种模式: n 系统号: n 系统号+服务号( ...
 - spring的依赖注入,为什么用接口的实现类而不是父类的继承类?
			
@Resource private EmployeeService employeeService; public void setEmployeeService(EmployeeService em ...
 - php-fpm优化
			
pid = run/php-fpm.pid #pid设置,默认在安装目录中的var/run/php-fpm.pid,建议开启 error_log = log/php-fpm.log #错误日志,默认在 ...
 - tomcat项目中文乱码问题解决方法
			
在部署tomcat项目时经常会遇到中文乱码问题,解决的方法可参考以下步骤. 1.更改Tomcat安装目录下的conf\server.xml,指定浏览器的编码格式为"utf-8"格式 ...
 - react-echarts之折线图的显示
			
react中想要实现折线图和饼图的功能,需要引入react-echarts包,然后再实现折线图的功能.我这里引用的版本是:0.1.1.其他的写法参echarts官网即可.下面详细讲解的是我在react ...
 - Using AlloyTouch to control  three.js 3D model
			
As you can see, the above cube rotation, acceleration, deceleration stop all through the AlloyTouch ...
 - sass安装
			
第一步:下载ruby http://www.ruby-lang.org/zh_cn/downloads/ 第二步:安装ruby http://www.ruby-lang.org/zh_cn/docum ...
 - IOS 开发小技巧总结
			
一.添加自定义字体 1.把字体文件拖到工程中. 2.plist 文件中添加字段:<Array>Fonts provided by application</Array> 把字体 ...
 - Android Weekly Notes Issue #233
			
Android Weekly Issue #233 November 27th, 2016 Android Weekly Issue #233 本期内容包括: 用Mockito做RxJava的单元测试 ...
 - Eclipse背景颜色设置(设置成豆沙绿色保护眼睛,码农保护色)
			
菜单栏windows–>preferences–>general–>editors–>text editors中在Appearance color options下修改 bac ...