手写服务器httpserver_封装分发器和多请求处理
来源:互联网 发布:柯维时间矩阵图 编辑:程序博客网 时间:2024/06/05 12:42
手写服务器httpserver_封装分发器
前面所述的分装请求和响应其实都只是对单个请求有效,如果需要对多个请求有效的话,就需要加入多线程。
import java.io.IOException;import java.net.ServerSocket;public class MyServer { private ServerSocket server ; private static final String CRLF = "\r\n"; private static final String blank = " "; private boolean flag = true; private int i = 0; public static void main(String[] args) { new MyServer().start(); } public void start(){ start(10001); } public void start(int port){ try { server = new ServerSocket(port); receive(); } catch (IOException e) {// e.printStackTrace(); stop(); } } public void receive(){ try { //请求及响应 while(flag){ new Thread(new Dispacher(server.accept())).start(); } } catch (IOException e) {// e.printStackTrace(); stop(); } } public void stop(){ try { flag = false; server.close(); } catch (IOException e) { e.printStackTrace(); } }}
import java.io.IOException;public class Servlet { public void service(Request req,Response re) throws IOException{ re.println("<html><head><title>HTML响应实例</title>"); re.println("</head><body>"); re.println("欢迎").println(req.getParameterValue("uname")); re.println("</body></html>"); }}
import java.io.IOException;import java.net.Socket;/** * 加入多线程,一个请求与响应,就一个对象 */public class Dispacher implements Runnable{ private Request req; private Response re; private Socket soc; private int code; public Dispacher(Socket soc) { this.soc = soc; try { req = new Request(soc.getInputStream()); re = new Response(soc); } catch (IOException e) {// e.printStackTrace(); code = 500; return ; } } @Override public void run() { Servlet s = new Servlet(); try { s.service(req, re); re.pushToClient(code); soc.close(); } catch (IOException e) {// e.printStackTrace(); try { re.pushToClient(500); soc.close(); } catch (IOException e1) { e1.printStackTrace(); } } }}
手写服务器httpserver_多请求处理_多态
如果我们有不同的Servlet,这个时候就需要加入多态的概念,也就是根据不同的请求,用不用的Servlet服务,这里利用工厂模式:客户端发送请求至服务器,服务器启动并调用 Servlet,Servlet 根据客户端请求生成响应内容并将其传给服务器,服务器将响应返回客户端。
一、先封装接收和发送消息
package cn.feng.http_2;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.StringTokenizer;public class Request2 { //请求方式 private String method; //请求资源 private String url; //请求参数 private Map<String,List<String>> parameterMapValues; //内部 public static final String CRLF = "\r\n"; private InputStream is; private String requestInfo; public Request2(){ method = ""; url = ""; parameterMapValues = new HashMap<String,List<String>>(); requestInfo = ""; } public Request2(InputStream is){ this(); this.is = is; try { byte[] data = new byte[204800]; int len = is.read(data); requestInfo = new String(data,0,len); } catch (IOException e) { return; } //分析请求信息 parseRequestInfo(); } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } /** * 分析请求信息 */ private void parseRequestInfo(){ if((null==requestInfo) || (requestInfo=requestInfo.trim()).equals("")){ return; } /** * ==================================== * 从信息的首行分解出:请求方式 请求路径 请求参数(get可能存在) * 如:GET /index.html?uname=intputUname&pwd=inputPassword HTTP/1.1 * * 如果为post方式,请求参数可能在最后正文中 * ==================================== */ String paramString = "";//接收请求参数 //1、获取请求方式 String firstLine = requestInfo.substring(0,requestInfo.indexOf(CRLF)); int idx = requestInfo.indexOf("/");// /的位置 this.method = firstLine.substring(0,idx).trim(); String urlStr = firstLine.substring(idx,firstLine.indexOf("HTTP/")).trim(); if(this.method.equalsIgnoreCase("post")){//post方式 this.url = urlStr; paramString = requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim(); }else if(this.method.equalsIgnoreCase("get")){//get方式 if(urlStr.contains("?")){ String[] urlArray = urlStr.split("\\?"); this.url = urlArray[0]; paramString = urlArray[1];//接收请求参数 }else{ this.url = urlStr; } } //2、将请求参数封装到Map中 parseParams(paramString); } /** * 将请求参数封装到Map中 * @param paramString */ private void parseParams(String paramString){ //分割,将字符串转成数组 StringTokenizer token = new StringTokenizer(paramString,"&"); while(token.hasMoreTokens()){ String keyValue = token.nextToken(); String[] keyValues = keyValue.split("="); if(keyValues.length == 1){ keyValues = Arrays.copyOf(keyValues, 2); keyValues[1] = null; } String key = keyValues[0].trim(); String value = null==keyValues[1]?null:decode(keyValues[1].trim(),"gbk"); //分拣,转换成Map if(!parameterMapValues.containsKey(key)){ parameterMapValues.put(key, new ArrayList<String>()); } List<String> values = parameterMapValues.get(key); values.add(value); } } /** * 解决中文 * @param value * @param code * @return */ private String decode(String value,String code){ try { return java.net.URLDecoder.decode(value, code); } catch (UnsupportedEncodingException e) { //e.printStackTrace(); } return null; } /** * 根据页面的name获取对应的多个值 */ public String[] getParameterValues(String name){ List<String> values = null; if( (values=parameterMapValues.get(name))==null ){ return null; }else{ return values.toArray(new String[0]); } } /** * 根据页面的name获取对应的单个值 */ public String getParameterValue(String name){ String[] values = getParameterValues(name); if(null==values){ return null; } return values[0]; }}
package cn.feng.http_2;import java.io.BufferedWriter;import java.io.IOException;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.Socket;import java.util.Date;/** * 封装响应信息 */public class Response2 { //两个常量 public static final String CRLF = "\r\n"; public static final String BLANK = " "; //流 private BufferedWriter bw; //正文 private StringBuilder content; //存储头信息 private StringBuilder headInfo; //存储正文长度 private int len = 0; public Response2(){ headInfo = new StringBuilder(); content = new StringBuilder(); len = 0; } public Response2(OutputStream os){ this(); bw = new BufferedWriter(new OutputStreamWriter(os)); } public Response2(Socket client){ this(); try { bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); } catch (IOException e) { headInfo = null; } } /** * 构建正文 */ public Response2 print(String info){ content.append(info); len += (info + CRLF).getBytes().length; return this; } /** * 构建正文+回车 */ public Response2 println(String info){ content.append(info).append(CRLF); len += (info + CRLF).getBytes().length; return this; } /** * 构建响应头 */ private void createHeadInfo(int code){ //1)HTTP协议版本、状态代码、描述 headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK); switch(code){ case 200: headInfo.append("OK"); break; case 404: headInfo.append("NOT FOUND"); break; case 500: headInfo.append("Server Error"); break; } headInfo.append(CRLF); //2)响应头(Response Head) headInfo.append("Server:test Server/0.0.1").append(CRLF); headInfo.append("Date:").append(new Date()).append(CRLF); headInfo.append("Content-type:text/html;charset=GBK").append(CRLF); //正文长度:字节长度 headInfo.append("Content-type:").append(len).append(CRLF); headInfo.append(CRLF); } /** * 推送到客户端 * @throws IOException */ public void pushToClient(int code) throws IOException{ if(null==headInfo){ code = 500; } createHeadInfo(code); //头信息+分割符 bw.append(headInfo.toString()); //正文 bw.append(content.toString()); bw.flush(); bw.close(); }}
二、封装不同的小服务器Servlet,利用多态,这样就可以通过父类去调用子类
import java.io.IOException;public abstract class Servlet2 { public void service(Request2 req,Response2 re) throws IOException{ doGet(req,re); doPost(req,re); } public abstract void doGet(Request2 req,Response2 re) throws IOException; public abstract void doPost(Request2 req,Response2 re) throws IOException;}
package cn.feng.http_2;import java.io.IOException;public class CopyOfLoginServlet extends Servlet2{ @Override public void doGet(Request2 req, Response2 re) throws IOException { String name = req.getParameterValue("uname"); String pwd = req.getParameterValue("pwd"); if(login(name, pwd)){ re.println("登录成功"); }else{ re.println("登录失败"); } } private boolean login(String name,String pwd){ return (name.equals("123"))&&(pwd.equals("456")); } @Override public void doPost(Request2 req, Response2 re) throws IOException { }}
package cn.feng.http_2;import java.io.IOException;public class RegisterServlet extends Servlet2{ @Override public void doGet(Request2 req, Response2 re) throws IOException { } @Override public void doPost(Request2 req, Response2 re) throws IOException { re.println("<html><head><title>返回注册</title>"); re.println("</head><body>"); re.println("你的用户名为").println(req.getParameterValue("uname")); re.println("</body></html>"); }}
三、主要工作:利用Map键与值之间的关系和多态来实现可以根据不同的请求实现不同的Servlet
package cn.feng.http_2;import java.util.HashMap;import java.util.Map;public class ServletContext { //为每一个Servlet取一个别名 //如:login-->LoginServlet,也就是本来可以通过login来调用LoginServlet private Map<String,Servlet2> servlet; //表示映射,也就是为login取一个别名 也就是url-->login //这样就可以通过很多个路径来获取login,因为Map的值是可以重复的 private Map<String,String> mapping; public ServletContext() { servlet = new HashMap<>(); mapping = new HashMap<>(); } public Map<String, Servlet2> getServlet() { return servlet; } public void setServlet(Map<String, Servlet2> servlet) { this.servlet = servlet; } public Map<String, String> getMapping() { return mapping; } public void setMapping(Map<String, String> mapping) { this.mapping = mapping; }}
package cn.feng.http_2;import java.util.Map;import cn.feng.http_1.Servlet;public class WebApp { private static ServletContext contxt; static{ contxt = new ServletContext(); Map<String,String> mapping = contxt.getMapping(); mapping.put("/login", "login"); mapping.put("/log", "login"); mapping.put("/reg", "register"); Map<String,Servlet2> servlet = contxt.getServlet(); servlet.put("login", new CopyOfLoginServlet()); servlet.put("register", new RegisterServlet()); } public static Servlet2 getServlet(String url){ if(null==url || (url=url.trim()).equals("")){ return null; } return contxt.getServlet().get(contxt.getMapping().get(url)); }}
四、利用多线程实现对Servlet的调用
package cn.feng.http_2;import java.io.IOException;import java.net.Socket;public class Dispacher2 implements Runnable{ private Request2 req; private Response2 re; private Socket soc; private int code=200; public Dispacher2(Socket soc) { this.soc = soc; try { req = new Request2(soc.getInputStream()); re = new Response2(soc); } catch (IOException e) {// e.printStackTrace(); code = 500; return ; } } @Override public void run() { try { //利用多态得到相应的Servlet,可以理解为Servlet2 ser = LoginServlet,或者Servlet2 ser = RegisterServlet //然后下面就是执行不用Servlet的功能 Servlet2 ser = WebApp.getServlet(req.getUrl()); if(null==ser){ code = 404; }else{ ser.service(req, re); } re.pushToClient(code); } catch (IOException e) { // e.printStackTrace(); this.code = 500; try { re.pushToClient(code); } catch (IOException e1) {// e1.printStackTrace(); } } try { soc.close(); } catch (IOException e) { e.printStackTrace(); } }}
package cn.feng.http_2;import java.io.IOException;import java.net.ServerSocket;public class MyServer2 { private ServerSocket server ; private static final String CRLF = "\r\n"; private static final String blank = " "; private boolean flag = true; public static void main(String[] args) { new MyServer2().start(); } public void start(){ start(10001); } public void start(int port){ try { server = new ServerSocket(port); receive(); } catch (IOException e) {// e.printStackTrace(); stop(); } } public void receive(){ try { while(flag){ new Thread(new Dispacher2(server.accept())).start(); } } catch (IOException e) {// e.printStackTrace(); stop(); } } public void stop(){ try { flag = false; server.close(); } catch (IOException e) { e.printStackTrace(); } }}
阅读全文
0 0
- 手写服务器httpserver_封装分发器和多请求处理
- 手写服务器httpserver_封装分发器_多请求处理_多态_反射JAVA202-204
- 手写服务器httpserver_封装Response_封装Request_JAVA199-201
- 手写服务器httpserver_准备_Socket入门_htmlJAVA195-196
- 手写服务器httpserver_准备_http协议_http工具JAVA197-198
- Rx处理服务器请求、缓存的完美封装
- Rx处理服务器请求、缓存的完美封装
- Rx处理服务器请求、缓存的完美封装
- Android 多个事件分发和处理
- retrofit2拦截器和请求封装
- twisted08 分发动态处理的http服务器
- linux高性能服务器编程之同时处理UDP请求和TCP请求的服务器
- 与服务器通信:发送请求和处理响应
- 第二章:与服务器通信发送请求和处理响应
- SuperSocket入门(一)-Telnet服务器和客户端请求处理
- Servlet---请求封装器
- 分发器与WEBrick服务器
- 服务器设计-处理并发请求
- URI,URL与URN的区别
- ConstraintLatout怎么用
- sap
- IE浏览器中的ajax缓存问题与new Date()兼容性问题的解决方法
- angularjs 页面权限控制
- 手写服务器httpserver_封装分发器和多请求处理
- zookeeper命令
- Windows安装Tensorflow
- filter和servlet区别
- 枚举的结构与应用
- __repr__作用
- C语言学习5:符号常量
- 随写一
- leecodeNo69之Sqrt(x)