声明:资料来自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; } } }}
- 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 index1) { return requestString.substring(index1+1, index2); } } return null; }}
- 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\r\n" //2.2响应数据写入输出流 + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + "File Not Found
"; output.write(errorMessage.getBytes()); } }catch(Exception e){ System.out.println(e.toString()); }finally { if(fis!=null){ fis.close(); } } } }
代码分析:
类的关系:HttpServer类与另两个类独立,response类组合了request类
对象关系:Httpserver传递socket输入流给request构造器,用于创建request对象,并调用其parse方法产生request对象属性值;传递已解析出属性值的request对象和socket输 出流给response;response对象根据request对象的属性(请求路径)去指定跟目录找请求资源,并处理。
结论:HttpServer的awai主程序管理了整个服务过程,生成请求,生成响应,执行响应处理;具体的响应处理由响应对象完成,负责根据请求路径自动地返回或有或无时的处理 结果!
很遗憾,当前没有能力以UML等更优雅或更符合业内标准的语言来描述,只能以文字说明,虽然我也很痛恨这种方法,但自己写的总算读来不困难,如果是读别人的,说实话很抵触,尤其是很多国内的书籍都是一大堆文字,个人很鄙视,好在我写来是给自己看的,而且下阶段的目标就是形式化描述。再次强调一下,形式化语言中代码其实是比数学公理化,符号化,逻辑推理更优雅进步的语言,这样的潦草描述,只能说是很个人色彩。