第三章 系统技术实现
3.1 Http连接管理组件
一个客户机与一个服务器要进行有效的通信,他们之间必然要遵守某种共同的协议,当前,浏览器和Web服务器之间大多采用超文本传输协议HTTP进行通信。HTTP协议是基于TCP/IP协议之上的应用层协议,具有无连接、无状态、面向对象等几个特点。HTTP协议基于请求/响应机制,其工作原理包括四个步骤。
1.连接:浏览器与服务器建立连接,打开一个称为套接字(socket)的虚拟文件,此文件的建立标志着连接建立成功。
2.请求:浏览器通过socket向服务器提交请求。
3.应答:服务器接收到该请求后,进行相应的事务处理,然后将处理结果通过HTTP传回给浏览器。
4.关闭连接:当应答结束后,服务器断开与浏览器的连接,以保证更多的浏览器能够与服务器建立连接。
Http连接管理组件位于DM WAS的最前端,它在服务器启动过程中获取服务器配置参数并初始化,负责监听端口,接收请求消息,并且将处理后的回复反馈给客户端。 3.1.1组件实现
Http连接管理组件基于HTTP协议,负责建立一个或多个服务器Socket并监听来自客户端的连接请求。当某个客户端发出连接请求时,它建立一个Socket对象,读出Socket输入输出流,将输入流进行解析并提取相关信息,然后实例化一个请求处理任务,并将输入输出流分别包装成request和response对象赋给该任务,交由线程池处理。流程图如图3.1所示。
图3.1 Http连接管理组件流程图
Http连接管理组件由LifeCycle、Server、HttpServer、ConnectionHandler、RequestHandler、Request、Response等类和接口以及实现线程池的相关类组成。
下面详细介绍一下相关的数据结构。 interface LifeCycle{
void start()throws LifeCycleException; void stop()throws LifeCycleException; boolean isStarted(); }
LifeCycle代表组件的生命周期接口,其目的是以一种一致的方式来管理组件的启动与停止。服务器中所有具有生命周期的组件如服务器类、应用程序上下文类都必须实现该接口。
interface Server extends LifeCycle{ String getServerInfo();
String getServerName(); int getServerPort(); String getAppBase();
URLClassLoader getWebappParentClassLoader(); }
Server代表整个服务器,它包含服务器的相关属性信息,负责服务器的启动与停止。
它由服务器启停组件调用。HttpServer类是对Server接口的实现,并扩展了对Servlet容器的接口。
class ConnectionHandler implements LifeCycle{ ServerSocket openSocket()throws LifeCycleException; void accept();
void handleConnection(Socket socket)throws IOException; }
ConnectionHandler实现了生命周期接口,它根据Server中的相关信息建立 ServerSocket,循环地接收客户端的连接请求。它获取客户端的Socket连接对象,读取输入输出流,然后交给RequestHandler任务处理。
class RequestHandler implements LifeCycle,Task{ void parseRequest(InputStream inputstream) void execute(Request request,Response response) }
RequestHandler同时实现了生命周期接口和Task接口,从而可以交给线程池处理。
RequestHandler解析输入流,读取HTTP请求头,将输入输出流包装成Request和Response对象,然后被ConnectionHandler放入线程池中,交由线程池执行。
interface Request extends javax.servlet.http.HttpServletRequest{ void setResponse(Response response); void setSocketInputStream(InputStream is); void addCookie(Cookie cookie);
void addHeader(String headerName,String headerValue); }
interface Response extends javax.servlet.http.HttpServletResponse{ void setRequest(Request request);
void setSocketOutputStream(OutputStream os); void writeHeaders()throws IOException; void flush()throws IOException; }
Request和Response是对Socket输入输出流的包装并实现了相关的Servlet接口,以一种对象的形式屏蔽了HTTP底层操作的细节。 3.1.2多线程
Web服务器应用程序常常要处理来自远程的大量而短小的任务,其特点是单个任务处理的时间很短而请求的数目却很大且很多请求是同时进行的。
显然单线程的处理机制无法满足我们的需求。在服务器程序中,使用多线程是提高服务器性能的捷径。实践证明,采用多线程设计可以极大地改善系统的响应性能,提高程序的并行性。
多线程,顾名思义就是在应用程序中使用多个线程。在服务器应用程序中 使用多线程的意思是对于接收的每一个请求我们使用一个单独的线程进行处理。构建多线程应用程序时,一个简单的方法是:每当一个请求到达时就创建一个新线程,然后在新建的这个线程中对该请求进行处理。实际应用中,这种方法的缺点是很明显的:为每个请求创建一个新线程的开销是很大的;创建过多的线程可能会导致系统由于内存消耗过度而导致系统资源不足。
资源不足是多线程应用中需要注意的一个问题。为了防止资源不足,服务器应对创建和销毁线程的次数进行合理的调整,尽量重用已有的线程。
池化技术被广泛的应用于服务器端软件的开发上。池化技术简单来说就是对已创建的对象放在一个池中进行缓存,将来需要某对象时,就从池中获取,从而达到重用对象的目的。线程池技术是池化技术的一种,当需要完成某项任务时,直接从线程池中取出线程来对任务进行处理,任务处理完后,将线程返回线程池,
其优点是:任务到达时,由于不需要新建线程,而是直接使用已有线程,提高了应用程序的响应速度。而且,通过适当地调整线程池中的最大线程数目和最小线程数目,可以防止系统资源不足问题。
3.1.2.1实现
在DM WAS中我们使用了多线程机制,对于单个的请求都交给线程池模块进行处理。我们使用事件驱动处理的方法实现线程之间的调度。在事件驱动处理的情况下,需要一种发信机制来控制某一特定线程何时应该运行。在Java中,可以使用wait()、notify()和notifyAll()方法向线程发送信号。这些方法允许线程在一个对象上阻塞,直到所需的条件得到满足为止,然后再次开始运行。这种设计减少了CPU占用,因为线程在阻塞时不消耗执行时间,并且可在notify()方法被调用时立即唤醒。与其它方法相比,事件驱动方法可以提供更短的响应时间。
线程池模块包括线程池、工作线程、任务队列、任务接口等几个部分。 class ThreadPool implements LifeCycle{ void initPool();//初始化线程池 void createWorker();//创建工作线程
void execute(Task task);//执行指定任务/*将工作线程返回到池中*/
void returnWorker(WorkerThread worker);/*通知线程池该任务发生异常,从而线程池可以结束该任务并回收该任务所占用的工作线程*/
void errorOccur(Task task); }
ThreadPool代表线程池,其作用是创建、销毁并管理线程,将工作线程放入线程池中,调用工作线程执行任务,销毁异常任务。
class WorkerThread implements Runnable{ void run();//运行工作线程 boolean overtime();//线程是否超时 }
WorkerThread代表一个工作线程,它是一个独立的可以循环执行任务的线程对象,在没有任务时进行等待(wait),在任务到达时被唤醒(notify)执行。
class TaskQueue{