一个由request/response构成的static web server

  声明:资料来自Tomcat剖析一书,该程序是基于java socket的,socket和stream类作为概念背景,现在仅仅是使用其作为基础类,并不关注其本身,关注点在一个服务器的外部功能和体系结构!

  • 代码目录

  

  • HttpServer 
package simpleserver;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 说明:   server该服务亲自管理request,和response,当前服务只是一个静态资源服务;
 *         request用来解析请求的数据流,抽象成请求对象
 *         response根据请求路径到根目录寻找资源,并输出;该程序的响应只有响应体
 * 
 * 作为一个静态服务器,该程序还需要完善:响应对象本身
 * @author Administrator
 *
 */
public class HttpServer {
    
    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 static void main(String[]args) {
        System.out.println("打印输出web_root"+WEB_ROOT);
        HttpServer serverSocket = new HttpServer();
        serverSocket.await();  //服务启动
    }
    
    public void await() {
        ServerSocket serverSocket = null;   
        int port = 8080;
        try {
            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("192.168.1.102"));//绑定服务的端口号,连接数量,要连接该服务的地址
        }catch(IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
        while(!shutdown) {
            Socket socket = null;
            InputStream input = null;
            OutputStream output = null;
            try {
                socket = serverSocket.accept();               //1在此监听,阻塞
                input = socket.getInputStream();  
                output = socket.getOutputStream();
                Request request = new Request(input);       //2把数据传递给request,令其解析;请求使用socket的输入流
                request.parse(); 
                Response response = new Response(output);   //3响应对象根据已解析的请求路径,寻找资源;响应使用socket的输出流
                response.setRequest(request);
                response.sendStaticResource();
                socket.close();                                //4发回响应后socket关闭;服务还在
                shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
            }
            catch(Exception e) {
                e.printStackTrace();
                continue;
            }
            
        }
        
    }
}
View Code
  • Request
package simpleserver;

import java.io.IOException;
import java.io.InputStream;
/**
 * @说明:对socket类的inputStream进行解析后生成诸多属性,隶属于该类
 * @author Administrator
 *
 */
public class Request {
    private InputStream input;
    private String uri;

    public Request(InputStream input) {   
        this.input = input;
    }

    public String getUri() {
        return uri;
    }

    public void parse() {
        StringBuffer request = 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++) {
            request.append((char)buffer[j]);
        }
        System.out.println(request.toString()); 
        uri = parseUri(request.toString());
        System.out.println("截取出来的路径"+uri);
    }
    private String parseUri(String requestString) { //只解析出请求数据中的uri属性
        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;
    }

}
View Code
  • Response
package simpleserver;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Response {
    private static final int BUFFER_SIZE =1024;
    Request request;
    OutputStream output;      
    public Response(OutputStream output) {
        this.output = output;
    }
    public void setRequest(Request request) {
        this.request = request;
    }
    
    
    public void sendStaticResource() throws IOException{
        byte[] bytes = new byte[BUFFER_SIZE];
        FileInputStream fis = null;
        try {
            File file = new File(HttpServer.WEB_ROOT, request.getUri());    //1根目录拼接请求路径
            System.out.println("请求路径"+file.getAbsolutePath());
            if(file.exists()){
                System.out.println("文件存在");
                fis = new FileInputStream(file); 
                int ch = fis.read(bytes, 0, BUFFER_SIZE);
                while(ch!=-1){
                    output.write(bytes, 0, ch);                             //2.1请求的响应数据写入输出流 
                    ch = fis.read(bytes, 0, BUFFER_SIZE);
                }
            }
            else {
                String errorMessage = "HTTP/1.1 404 File Not Found
"     //2.2响应数据写入输出流
                        + "Content-Type: text/html
"
                        + "Content-Length: 23
"
                        + "
"
                        + "<h1>File Not Found</h1>";
                output.write(errorMessage.getBytes());
            }
        }catch(Exception e){
            System.out.println(e.toString());
        }finally {
            if(fis!=null){
                fis.close();
            }
        }
        
    }

        

}
View Code

 代码分析:

  类的关系:HttpServer类与另两个类独立,response类组合了request类

  对象关系:Httpserver传递socket输入流给request构造器,用于创建request对象,并调用其parse方法产生request对象属性值;传递已解析出属性值的request对象和socket输         出流给response;response对象根据request对象的属性(请求路径)去指定跟目录找请求资源,并处理。

  结论:HttpServer的awai主程序管理了整个服务过程,生成请求,生成响应,执行响应处理;具体的响应处理由响应对象完成,负责根据请求路径自动地返回或有或无时的处理       结果!

很遗憾,当前没有能力以UML等更优雅或更符合业内标准的语言来描述,只能以文字说明,虽然我也很痛恨这种方法,但自己写的总算读来不困难,如果是读别人的,说实话很抵触,尤其是很多国内的书籍都是一大堆文字,个人很鄙视,好在我写来是给自己看的,而且下阶段的目标就是形式化描述。再次强调一下,形式化语言中代码其实是比数学公理化,符号化,逻辑推理更优雅进步的语言,这样的潦草描述,只能说是很个人色彩。

原文地址:https://www.cnblogs.com/10000miles/p/9211231.html