JSP和Servlet那些事儿系列--初探HTTP服务器
? 《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服务器默认的监听主机和端口、默认的文档根路径、默认处理线程数、默认配置文件等。
?
?? 处理线程类:?????? 处理线程持有以上主线程的taskQueue引用,然后不断从该队列中获取socket,获得socket之后便实例化HttpRequest和HttpResponse对象,并调用HttpRequest的parse方法进行请求解析,根据解析结果查找本地资源,如果请求的资源存在,那么就把本地资源对应的流传递给HttpResponse,由HttpResponse进行读取,HttpResponse读取到的流全部回写到客户端,从而完成请求。
?
? 以上代码基本具备了HTTP请求处理能力,为了尽可能的简化和描述出HTTP服务器最本质的东西,省略了很多处理(比如静态资源缓存,HTTP头处理等)。验证HTTP服务器步骤:
? 1,新建一个server.properties文件,并正确配置主机、端口等
??? ---
??? host=localhost
??? port=8080
??? docRoot=./webapps
??? threadCount=10? 2,需要保证server.properties文件中配置的docRoot目录存在,拷贝一些静态文件(html...)到docRoot目录下
? 3,java lesson1.server.HttpServer启动
? 4,通过浏览器输入http://$host:$port/$resourceName便可,其中resourceName为相对于server.properties中配置的docRoot目录的相对路径。可以使用firefox的httpwatch查看请求和响应的细节。