日期:2014-05-16 浏览次数:20435 次
? 《JSP和Servlet那些事儿 》系列文章旨在阐述Servlet(Struts和Spring的MVC架构基础)和JSP内部原理以及一些比较容易混淆的概念(比如forward和redirect区别、静态include和<jsp:include标签区别等)和使用,本文为系列文章之启蒙篇--初探HTTP服务器,基本能从本文中折射出Tomcat和Apache HTTPD等处理静态文件的原理。敬请关注连载!
?
? 在学习Servlet和JSP的过程中,如果对HTTP协议本身以及HTTP服务器运行原理有初步的认识的话,这会使得后边的学习更加容易。HTTP服务器本身的内部原理对于Java而言是比较简单的,就是一个Socket处理;请求的解析就是Socket InputStream的读取和分析,所谓的响应仅仅是按照HTTP协议规定的顺序把字节流写入到Socket OutputStream里面。以下是一个简单的HTTP服务器,希望读者在阅读代码的过程中能够想起RFC2616的一些相关术语、或者能够很容易的理解代码。
?
? 一个简单的HTTP服务器需要注意以下几点 :
? 1,HTTP服务器监听主机和端口:也就是Java Socket的监听主机和端口
? 2,DocRoot:也就是文档根路径,就是http服务器查找客户端请求资源的根路径。
? 3,处理线程:需要有至少一个处理线程用于解析Socket输入流及回写请求到Socket输出流,Socket输出流就是发给客户端的通道
?4,以上配置最好提供配置文件(类似具有HTTP服务功能的tomcat配置文件conf/server.xml,Apache HTTPD的httpd.conf文件)
?
? 根据以上几点,Java实现基本的HTTP服务器的思路如下 :
? 1,需要写一个类,代码全局的HTTP服务器配置(端口,线程数等);对应本文中Configure类
? 2,需要一个Main类,实质就是主线程,主线程需要绑定ServerSocket用于监听客户端请求,并启动多个处理线程处理客户端Socket请求; 对应本文中的HttpServer类
? 3,需要多个处理线程,用于处理主线程分配的Socket处理任务; 对应本文中的ProcessThread类
? 4,需要一个专门用于解析HTTP请求的类,该类从Socket中获取到输入流,然后读取输入流中的字节,从而解析出客户端希望请求的资源; 对应本文中的HttpRequest类
? 5,需要一个专门回写请求的类,把客户端请求的资源对应的文件流输出到Socket的输出流,如果资源找不到的话,就返回404给客户端; 对应本文中的HttpResponse类
? 以下是全部的代码:
?
??? 主要定义了一些常量,比如HTTP服务器默认的监听主机和端口、默认的文档根路径、默认处理线程数、默认配置文件等。
?
package lesson1.server; public final class Constants { /** * Listener's default values. */ public final static String DEFAULT_HOST = "localhost"; public final static int DEFAULT_PORT = 8080; public final static String DEFAULT_DOC_ROOT = "./webapps"; /** * Default work thread count. */ public final static int DEFAULT_WORKER_COUNT = 10; public static final byte CR = (byte) '\r'; public static final byte LF = (byte) '\n'; public static final byte SP = (byte) ' '; public static final byte HT = (byte) '\t'; public static final String CRLF = "\r\n"; public static final byte COLON = (byte) ':'; public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1"; public static final int HTTP_MESSAGE_404 = 404; public static final int HTTP_MESSAGE_200 = 200; public static final int HTTP_MESSAGE_500 = 500; public static final int HTTP_MESSAGE_503 = 503; public static final String DEFAULE_CONFIG_FILE ="server.properties"; public static final String CONFIG_HOST = "host"; public static final String CONFIG_PORT ="port"; public static final String CONFIG_DOCROOT ="docRoot"; public static final String CONFIG_THREAD_COUNT ="threadCount"; }?
??? 该类主要负责从配置文件中读取到HTTP服务器的监听主机、端口、DocRoot等重要信息。HTTP服务器的其他代码全部都会应用这个类的属性。
?
package lesson1.server; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; /** * HTTP服务器全局配置项 * * @author sta * */ public class Configure { // listening host private String host = Constants.DEFAULT_HOST; // listening port private int port = Constants.DEFAULT_PORT; // Document Root which locate the static resource private String docRoot = Constants.DEFAULT_DOC_ROOT; /** * Http Server config file path */ private String configFile = Constants.DEFAULE_CONFIG_FILE; /** * Worker thread count. */ private int workerCount = Constants.DEFAULT_WORKER_COUNT; // 发送HTTP响应的缓冲区大小 private static final int DEFAULT_SEND_BUFFER_SIZE = 8 * 1024; // default 8k private int sendBufferSize = DEFAULT_SEND_BUFFER_SIZE; private static final Configure instance = new Configure(); // for singleton private Configure() { Properties properties = new Properties(); InputStream in = null; try { in = new FileInputStream(configFile); pr