手写服务器(二)
封装
1、Response
2、Request
3、多线程处理
一、封装Response
CloseUtil.java (关闭流的方法)
package cn.server; import java.io.Closeable; import java.io.IOException; /* * 关闭流的方法 */ public class CloseUtil { public static void closeAll(Closeable... io) { for(Closeable temp:io) { try { if(null!=temp) { temp.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
Response.java (封装Response)
package cn.server; 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 Response { 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 Response() { headInfo=new StringBuilder(); content=new StringBuilder(); len=0; } public Response(Socket client) { this(); try { bw=new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); } catch (IOException e) { // TODO Auto-generated catch block headInfo=null; } } public Response(OutputStream os) { this(); bw=new BufferedWriter(new OutputStreamWriter(os)); } /* * 构建正文 */ public Response print(String info) { content.append(info); len+=info.getBytes().length; return this; } /* * 构建正文+回车 */ public Response 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("SEVER ERROR"); break; } headInfo.append(CRLF); //2)响应头(response Head) headInfo.append("sun").append(CRLF); headInfo.append("Date").append(new Date()).append(CRLF); headInfo.append("Content-type:text/html;charset=GBK").append(CRLF); //正文的长度 :字节长度 headInfo.append("Content-Length:").append(len).append(CRLF); headInfo.append(CRLF); //分隔符 } //推送到客户端 void pushToClient(int code) throws IOException { if(headInfo==null) { code=500; } createHeadInfo(code); //头信息+分割符 bw.append(headInfo.toString()); //正文 bw.append(content.toString()); bw.flush(); } public void close() { CloseUtil.closeAll(bw); } }
Server4.java (调用)
package cn.server; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; /* * 创建服务器,并启动 * 请求并响应 */ public class Server4 { private ServerSocket server; public static final String CRLF="\r\n"; public static final String BLANK=" "; public static void main(String[] args) { Server4 server=new Server4(); server.start(); } //启动方法 public void start() { try { server = new ServerSocket(8660); this.receive(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* * 接收客户端 */ private void receive() { try { Socket client=server.accept(); String msg=null; byte[] data=new byte[20480]; int len=client.getInputStream().read(data); //接收客户端的请求信息 String requestInfo=new String(data,0,len).trim(); System.out.println(requestInfo); //响应 Response rep=new Response(client); rep.println("<html><head><title>http响应实例</title><head>" ); rep.println("<body><p></p>Hello Server!</body></html>"); rep.pushToClient(200); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* * 停止服务器 */ public void stop() { } }
二、封装Request (解决中文乱码问题)
Request.java (封装Request)
package cn.server; 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; /* * 封装Request */ public class Request { //请求方式 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 Request() { method=""; url=""; parameterMapValues=new HashMap<String,List<String>>(); requestInfo=""; } public Request(InputStream is) { this(); this.is=is; try { byte[] data=new byte[20480]; int len = is.read(data); requestInfo=new String(data,0,len); } catch (IOException e) { return ; } //分析头信息 paseRequestInfo(); } /* * 分析请求信息 */ private void paseRequestInfo() { if(null==requestInfo ||(requestInfo=requestInfo.trim()).equals("")) { return ; } /* * 从信息的首行分解出:请求方式 请求路径 请求参数(get可能存在) * * */ 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")) { this.url=urlStr; paramString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim(); }else if(this.method.equalsIgnoreCase("get")) { if(urlStr.contains("?")) { //是否存在参数 String[] urlArray=urlStr.split("\\?"); this.url=urlArray[0]; paramString=urlArray[1]; //接收请求参数 }else { this.url=urlStr; } } //2、将请求参数封装到Map中 //如果paramString请求参数不存在 if(paramString.equals("")) { return ; } parseParams(paramString); } private void parseParams(String paramString) { //分割 将字符串转成数组 StringTokenizer token=new StringTokenizer(paramString,"&"); while(token.hasMoreTokens()) { String keyValue=token.nextToken(); String[] keyValues=keyValue.split("="); //[uname,123] if(keyValues.length==1) { keyValues=Arrays.copyOf(keyValues, 2); //数组拷贝 keyValues=[uname] 把以前的值放进去,长度变为2 keyValues[1]=null; } String key =keyValues[0].trim(); String value=keyValues[1]==null?null:decode(keyValues[1].trim(),"utf-8"); //转换成Map,分拣 if(!parameterMapValues.containsKey(key)) { parameterMapValues.put(key,new ArrayList<String>()); } List<String> values=parameterMapValues.get(key); values.add(value); //{uname=[123],pwd=[213],fav=[1],fav=[2] } } /* * 解决中文乱码 * 解码 */ private String decode(String value,String code) { try { return java.net.URLDecoder.decode(value,code); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block } return null; } /* * 根据页面的 name获取对应的多个值 */ public String[] getParametervalues(String name) { List<String> values=null; values=parameterMapValues.get(name); if(values==null) { return null; }else { return values.toArray(new String[0]); //将list转变为数组 } } /* * 根据页面的 name获取对应的值 */ public String getParameter(String name) { String[] values=getParametervalues(name); if(values==null) { return null; } return values[0]; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
Server5.java (调用)
package cn.server; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; /* * 创建服务器,并启动 * 请求并响应 */ public class Server5 { private ServerSocket server; public static final String CRLF="\r\n"; public static final String BLANK=" "; public static void main(String[] args) { Server5 server=new Server5(); server.start(); } //启动方法 public void start() { try { server = new ServerSocket(8290); this.receive(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* * 接收客户端 */ private void receive() { try { Socket client=server.accept(); String msg=null; //请求 Request req=new Request(client.getInputStream()); //响应 Response rep=new Response(client); rep.println("<html><head><title>http响应实例</title>" ); rep.println("<head><body>"); rep.println("欢迎:").println(req.getParameter("uname")).println("回来"); rep.println("</body></html>"); rep.pushToClient(200); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* * 停止服务器 */ public void stop() { } }
效果: