读书人

tomcat解析之简略web服务器(图)

发布时间: 2012-10-24 14:15:58 作者: rapoo

tomcat解析之简单web服务器(图)

??? 之前有javaeyer推荐了一本书《how tomcat works》,今天晚上看了看,确实不错,第一眼就着迷了。 于是乎就学着书上的例子敲了敲,学会了一个简单web服务器的大概实现,当然,这个简直就无法称之为web服务器,但是也算是走进web服务器的第一步吧。

???? 这篇文章仅限于学习记录,文笔凌乱之处,还望各位见谅。 OK,下面进入正题;

????? 开始之前,首先我们要清楚以下几个内容。

?

??? ?首先,一个最简单服务器包括三个部分:
???? web服务器----HttpServer
??????????????? 请求---Request
???? ?????????? 响应---Response

?

? ?? 这个服务器如何使用:
????? 1. 请求静态资源 通过 http://localhost:8090/index.html?
??????????????????? 成功 则返回页面, 否则会返回 File Not Found 的错误信息.
?????? PS:比如上面的index.html 必须放在一个webroot目录下.
????
????? 2. 服务器的关闭通过uri来处理
??????? 通过http://lcoalhost:8090/SHUTDOWN 这个Uri来停止服务器.

???
?? 需要注意的其他几个知识点:
????? 1. HTTP/1.1 协议的知识。? 比如 请求,响应的结构。 发送与接收形式等.
????? 2. Java中网络的相关只是???? ServerSocket 与 Socket 的使用.

?

?OK, 放上代码, 代码只有3个类,都挺简单的, 这个应用只是一个最最简单的雏形:

?

?主类: HttpServer

?

package chapter1.simplewebserver;import java.io.File;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.InterfaceAddress;import java.net.ServerSocket;import java.net.Socket;/** *  *  下午11:59:29 * @author gogole_09 * 简单web服务器 */public class HttpServer {//定位到webroot目录public static final String WEB_ROOT=System.getProperty("user.dir")+File.separator+"webroot";//停止命令private static final String SHUTDOWN_COMMAND="/SHUTDOWN";//是否接收到了关闭命令private boolean shutdown=false;/** * 等待命令 */public void await(){ServerSocket serverSocket=null;int port=8090;try {serverSocket=new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));} catch (Exception e) {e.printStackTrace();System.exit(1);}//监听端口,等待请求。while(!shutdown){Socket socket=null;InputStream input=null;OutputStream output=null;try {socket=serverSocket.accept();//输入流 有过jsp编程的哥们都知道这是干嘛的input=socket.getInputStream();//输出流output=socket.getOutputStream();//构建请求Request request=new Request(input);//解析请求信息request.parse();//响应类Response response=new Response(output);response.setRequest(request);response.sendStaticResource();//处理完毕,关闭 socket.close();//检查提供的URI是否为shutdown命令shutdown=request.getUri().equals(SHUTDOWN_COMMAND);} catch (Exception e) {e.printStackTrace();continue;}}}public static void main(String[] args) {HttpServer server=new HttpServer();server.await();}}

?

接下来是请求类:?

?? Request

?

package chapter1.simplewebserver;import java.io.IOException;import java.io.InputStream;/** *  *  上午12:09:36 * @author gogole_09 *  简单服务器的请求类 */public class Request {private InputStream input;private String uri;public Request(InputStream in) {this.input=in;}/** * 解析Uri操作 */public void parse() {StringBuffer buf=new StringBuffer();int i;byte[] buffer=new byte[2048];try {i=input.read(buffer);} catch (IOException e) {e.printStackTrace();i=-1;}for(int j=0;j<i;j++){buf.append((char)buffer[j]);}System.out.println(buf.toString());uri=parseUri(buf.toString());}/** * 解析Uri   *  为什么要以' '为做标识 , 这里需要了解HTTP协议的相关结构; *   一个请求行 以 请求方法开头 + 请求URI+ 请求协议版本 + CRLF字符结束 *    比如,你请求index.html 用GET方式 ,那么Uri形式为: *     *    GET /index.html HTTP/1.1 *     *     * @param requestString * @return */private String parseUri(String requestString){int index1,index2;index1=requestString.indexOf(' ');if(index1!=-1){index2=requestString.indexOf(' ',index1+1);if(index2>index1){return requestString.substring(index1+1,index2);}}return null;}public String getUri() {return uri;}}

?

?

?有了请求了,服务器就得响应啊,试想,我发个请求没反应,你的第一反应是不是想砸电脑呢?

?OK,Response类来了。

?

package chapter1.simplewebserver;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;/** *  * 上午12:10:58 *  * @author gogole_09 简易服务器的响应类 */public class Response {/** * HTTP响应格式:= Status-Line * *((general-header|response-header|entity-header)CRLF) CRLF [message-body] * Status-Line=HTTP-Version SP(空格) Status-Code SP Reason-Phrase CRLF *  */private static final int BUFFER_SIZE = 1024;Request request;private OutputStream output;public Response(OutputStream output) {this.output = output;}public void setRequest(Request request) {this.request = request;}/** * 服务器解析并发送静态资源 * @throws IOException */public void sendStaticResource() throws IOException {byte[] bytes = new byte[BUFFER_SIZE];FileInputStream fis = null;try {File file = new File(HttpServer.WEB_ROOT, request.getUri());if (file.exists()) {fis = new FileInputStream(file);int ch = fis.read(bytes, 0, BUFFER_SIZE);while (ch != -1) {output.write(bytes, 0, ch);ch = fis.read(bytes, 0, BUFFER_SIZE);}} else {//文件没找到String errorMessage = "HTTP/1.1 404 File Not Found\r\n"+ "Content-Type:text/html\r\n"+ "Content-Length:23\r\n"+"\r\n<ht>File Not Found</h1>";output.write(errorMessage.getBytes());}} catch (Exception e) {System.out.println(e.toString());}finally{if(fis!=null)fis.close();}}}

?

?

?

?OK,现在这个应用可以运行了,但是你运行起来,没办法用,为什么, 因为还需要有用户请求的静态资源。

? 在HttpServer类中,我们hard code了一个webroot目录,约定把所有的静态资源都放到这个目录下面的。

??下面我们就把这个目录建好,并放一点资源进去 ,我是这样放的, 如图:

?
tomcat解析之简略web服务器(图)

?

?index.html 中 就只有一行代码:

?
tomcat解析之简略web服务器(图)

?

?

?OK, 下面我们运行一下 HttpServer ,得到页面 如下图:

?
tomcat解析之简略web服务器(图)

? 在控制台,你将会看到程序打印出:

?
tomcat解析之简略web服务器(图)

?

?

?接着,我们尝试请求一个不存在的资源:?? 我们会的到一个404的错误页面.

?
tomcat解析之简略web服务器(图)

OK, 一个简单的web服务器就完成了, 虽然简单,但是我们可以通过这个了解一个大概的流程。

?以及复习一下java net包与HTTP/1.1协议的一些知识。

?

也希望这个篇文章对都有需要的人有帮助。

?

?

?PS: 最近有很多朋友都问这本书哪里有买,我本人并非看的纸质的,而是电子版的, 需要下载的可以去新浪共享频道找找, 我的是从哪里下来的, 中文书名就叫 <tomcat工作原理>

1 楼 曾经de迷茫 2010-02-06 请问楼主浏览器上装的什么东东,看请求资源的那个? 2 楼 gogole_09 2010-02-06 曾经de迷茫 写道请问楼主浏览器上装的什么东东,看请求资源的那个?
是Http Watch. 查看请求url,传递的参数,以及服务器返回数据的好东西。 3 楼 wanggp 2010-02-07 应该是how tomcat works 4 楼 elgs 2010-02-07 how tomcat works在中国买不到,这么好的书。 5 楼 gogole_09 2010-02-08 wanggp 写道应该是how tomcat works
嘿嘿,是的。 书名写错了,马上修正。 6 楼 smartman_jc 2010-02-10 不错!学习了,受益匪浅 7 楼 hellojinjie 2010-02-16 为何不用 NIO 来实现呢,, 8 楼 fantasybei 2010-02-18 也没你说得那么好,一般般吧,有些东西说得太罗嗦. 9 楼 mercyblitz 2010-03-22 Tomcat 不也是处理Socket吗? 10 楼 sw1982 2010-03-22 比较精华的地方是启动、关闭操作。。
占用一个port监听关闭命令,呵呵。 这里可以对java项目的友好关闭做一下处理 11 楼 gogole_09 2010-03-25 mercyblitz 写道Tomcat 不也是处理Socket吗?
tomcat内部也是处理socket的, 不知有什么不对吗? 12 楼 gogole_09 2010-03-25 sw1982 写道比较精华的地方是启动、关闭操作。。
占用一个port监听关闭命令,呵呵。 这里可以对java项目的友好关闭做一下处理
这个port监听不止是单独处理关闭,所有的请求都通过端口的,只是为了简单,根据URI来确定是否关闭。 实际在tomcat内部,还用到了ShutDownHook这个东西来处理 tomcat的关闭。 有兴趣的可以看看how tomcat works的ShutDownHook这个章节。 呵呵, 欢迎交流。 13 楼 sw1982 2010-03-26 刚好受这个帖子推荐看到shutdownhook这个玩意,可是这个东东只能处理本身正在运行的进程退出。
现在的场景是我用sh脚本nohup启动一个java进程后台运行,然后怎么友好关闭这个线程呢? 最简单的就是向一个端口发stop请求。

gogole_09 写道sw1982 写道比较精华的地方是启动、关闭操作。。
占用一个port监听关闭命令,呵呵。 这里可以对java项目的友好关闭做一下处理
这个port监听不止是单独处理关闭,所有的请求都通过端口的,只是为了简单,根据URI来确定是否关闭。 实际在tomcat内部,还用到了ShutDownHook这个东西来处理 tomcat的关闭。 有兴趣的可以看看how tomcat works的ShutDownHook这个章节。 呵呵, 欢迎交流。
14 楼 nbnxyuyun 2010-06-12 public static final String WEB_ROOT=System.getProperty("user.dir")+File.separator+"webroot";中user.dir如何设,我试了无法侦测到8090端口.

读书人网 >Web前端

热点推荐