发信人: zjxyz(xyz)
整理人: zjxyz(2002-04-10 19:11:20), 站内信件
|
首先说明一下,我的设计并不是什么很好的设计,至少目前还存在不少不规范的地方,例如我没有刻意的为了实现代码可扩充、维护而把一些地方写成松耦合;在我看来,工作之外的编程是一件很愉快的事情,没有必要把自己搞得那么辛苦。这样的程序有一个好处就是,代码比较适合初学者阅读,我本身出发的目的就是如此。
这是一个参考例子,让大家可以迅速的知道怎么用Java写一个WEB服务器,过程是怎样的。我这组文章是面向代码的,我很讨厌某些人开口就谈编程思想,而一谈到显得就一副不耐烦的样子;我始终认为,代码实现不了的思想,就是废话。这篇文章就是讨论代码的实现,讨论的思想是当前代码可以实现的思想,其他废话,免谈。
一、请求与响应的对象:
上面提到,服务器跟浏览器互交时,主要有两个步骤,就是接收浏览器请求,响应浏览器的请求,所以我们在设计类的时候,可以把这两个步骤抽象成两个类:请求类HttpRequest,响应类HttpResponse。工作过程大致是这样的:
我在HttpRequest、HttpResponse之上设计一个HttpHandler类,用于调度对浏览器的响应;在侦听服务器侦听到一个连接后,就把通过某些方式把Sokcet句柄传给HttpHandler类的实例,然后由HttpHandler的实例把Soket句柄传给一个HttpRequest的实例;经过HttpRequest处理后,HttpHandler根据HttpRequest处理的结果,经过处理后,HttpHandler调度HttpResponse的实例响应浏览器。
下面详细介绍 HttpHandler 工作的情况,根据HttpRequest处理的结果,我们分几种情况处理:
1、 静态的页面的请求,这时 HttpHandler 将生成 staticsou 的实例,并把HttpRequest、HttpResponse的实例传给staticsou 的实例,后面处理请求的工作就交给 staticsou 完成了,当处理完毕或者处理出错,程序会返回到 HttpHandler,然后 HttpHandler 会做一些善后处理工作;
2、 CGI请求,这时 HttpHandler 将生成 cgiRunTime的实例来处理相关的请求,过程跟静态的页面的请求类似;
3、 聊天室请求,这时 HttpHandler 将生成 chat 的实例,并把HttpRequest、HttpResponse的实例传给chat 的实例,不过聊天处理跟上面的处理略有不同,就是客户端的socket连接在该 HttpHandler 实例销毁时,并没有销毁,而是保存在侦听服务实例的一个Hash表里面,当有用户发信息上聊天室时,系统会遍历整个Hash表,把信息发到各个连接去。
4、 代理请求,这时 HttpHandler 将生成 j2proxy 的实例,并把HttpRequest、HttpResponse的实例传给j2proxy 的实例,而j2proxy会分析HttpRequest里面的信息,连接远程的WEB服务器,然后把把WEB 的资源取回来然后通过HttpResponse的实例转发给客户端。
上面所述的是客户端的一个连接请求发到服务器时,服务器所做的工作的过程,当然,我为了实现比较高的性能,我使用的多实例,多线程的手段。下面将简述我在这方面的设计思想。
二、服务器实例
系统的主类是从 org.zjxyz.j2wsp.j2wsp 开始的。
而运行系统之前,必须按要求(请参阅附录1)写好配置文件,放一个目录里面,一个目录及目录里面的配置文件就为系统提供了一个实例的配置。
当j2wsp的main 方法执行时,系统就会搜索配置目录下的子目录,将实例的配置逐个读出,然后根据实例的配置的生成若干服务线程,每个服务线程负责侦听不同的端口,而每个服务线程根据实例的配置又生成若干个处理线程,用于响应服务连接。当有客户连接入侦听的端口时,服务进程通过调度唤醒文章某个处理线程来响应客户的请求,这样的话,每个服务线程就能同时处理多个连接请求。
大概设计思想就是如此,不算特别复杂,具体的实现,我在后面中将逐一介绍。
附录一、
设置与运行
j2wsp中实例的含义
j2wsp是按侦听的端口来划分实例的,在j2wsp中,所谓实例,就是由一个侦听线程和一组响应线程所组成的线程集合,每一个实例负责侦听一个端口,不同的实例拥有独立的配置文件,以提供有别于其他实例的服务。
安装好的j2wsp在 j2wsp/conf/ 目录下有几个子目录,这些都是实例的配置目录,每个子目录里面都有三个文件分别是:
chatinit.txt --聊天室初始化信息
mime.types --mime类型定义文件
httpd.conf --实例配置文件
实例的配置目录的目录名是随意起的,只要放在 j2wsp/conf/ 目录下面就可以了,每个正确配置目录的实例必须包含上述文件。当j2wsp启动时,会去j2wsp/conf/目录读取各子目录下的配置文件,创建实例。
实例的管理
如果要创建一个新的实例,只需要在 j2wsp/conf/ 建立一个新的目录,把上述三个文件copy进去,然后依照运行的需要对 httpd.conf 文件进行修改,重新启动j2wsp即可。
如果要删除一个实例,只把要删除的实例的配置目录删掉,重重新启动j2wsp即可。
配置 httpd.conf
以下是一个完整的 httpd.conf 内容,
############################################
Port 8000
backlog 100
MaxKeepAliveRequests 20
DocumentRoot ..\htdocs
DefaultType text/plain
DirectoryIndex index.html index.htm
AddHandler cgi-script .cgi .pl
ScriptAlias /cgi-bin/ ../cgi-bin/
#############################################
配置文件的规则:
主要格式与 apache 的配置文件相似:
采用[名字][空格][值][空格][值]来描述一个配置项的内容;
[名字]不区分大小写;
文件中间允许空行;
允许在配置文件里用 # 来注释一行内容;
要注意的是,上述配置项都是缺一不可的,因为程序没有判断某个配置项是否为空,所以,当缺少配置项时,程序运行的过程中会抛出空指针的异常。
下面就逐个解释配置项名含义:
Port 实例侦听的端口,不允许与其他实例相同;
backlog 侦听队列的最大等待连接数目;
MaxKeepAliveRequests 该实例的服务线程数目,该数字的大小涉及到消耗的内存多少
DocumentRoot Web服务器的根目录
DefaultType 默认返回给浏览器的数据类型
DirectoryIndex 默认的页面
AddHandler 从第二个值开始,是被当作CGI处理的脚本文件的类型
ScriptAlias 第一个值是 CGI 的影射路径,第二个值是CGI实际路径
---- 网易广州社区Java版
XYZ个人主页,提供一个公开源代码的WEB服务器+聊天室
冗談の言葉は无用だ…俺は最强だ!あんた ゃるじゃないか.だが...,世界じゃ二番目だ.
手机号码归属地查询系统,可查出手机所属省份,所属城市,SIM卡类型,网友做的。

|
|