手写Web服务器
涉及到的知识点
OOP、容器、IO流、多线程、网络编程、XML解析、反射、html、http
WebServer简介
- 上网浏览网页,离不开服务器,客户请求页面,服务器响应内容。都是基于HTTP协议。
- Web请求都是使用Request和Response式的交流
反射
反射Reflection:把Java类中的各种结构方法、属性、构造器、类名映射成一个个Java对象。利用反射技术可以对一个类进行解剖,反射是框架设计的灵魂。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package zhuchuli.server;
import java.lang.reflect.InvocationTargetException;
public class ReflectTest01 {
public static void main(String[] args) throws Exception{ Class clz=new Iphone().getClass(); clz=Iphone.class; clz=Class.forName("zhuchuli.server.Iphone"); Iphone iphone=(Iphone)clz.getConstructor().newInstance(); System.out.println(iphone);
}
} class Iphone{ public Iphone() {}; }
|
XML解析
- 解析流程(按流的方式进行解析)
- 获取解析工程:
SAXParserFactory factory = SAXParserFactory.newInstance();
- 获取解析器:
SAXParser parser = factory.newSAXParser();
- 编写处理器,加载文档document注册处理器:
PHandler handler = new PHandler();
- 解析:
parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("zhuchuli/server/p.xml"), handler);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package zhuchuli.server;
import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler;
public class XMLTest01 { public static void main(String[] args) throws Exception { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); PHandler handler = new PHandler(); parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("zhuchuli/server/p.xml"), handler);
} } class PHandler extends DefaultHandler{ @Override public void startDocument() throws SAXException { System.out.println("************** 解析文档开始 ******************"); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println(qName+"------>"+"解析开始"); } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents=new String(ch,start,length).trim(); if(contents.equals("")) { System.out.println("内容为 --->"+"空"); }else { System.out.println("内容为 --->"+contents); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println(qName+"------>"+"解析结束"); } @Override public void endDocument() throws SAXException { System.out.println("**************解析文档结束******************"); } }
|
html
html:HyperText Markup Language:超文本标记语言,简单理解为浏览器使用的语言。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>第一个html页面</title> </head> <body> <h1>表单的使用</h1> <pre> name: web服务器使用的属性<br> id: 前端js使用的属性<br> action:请求web服务器的资源 <br> method: get/post<br> get:从服务器端获取数据,默认发送行为,发送数据量不宜较大,不安全,请求参数跟在url上<br> post:向服务器端发送数据,发送数据量相对较大,安全,请求参数在请求体中 </pre> <form method="post" action="https://localhost:8888/index.html"> 用户名:<input type="text" name="uname" id="uname" /><br> 密码:<input type="password" name="pswd" id="pswd" /><br> <input type="submit" value="提交"/> </form> </body> </html>
|
HTTP协议
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,所以的WWW文件都必须遵守这个标准。
- 请求协议
- 请求行:方法(GET/POST) URI 协议/版本;
- 请求头:(Request Header)
- 请求正文:
- 响应协议
- 状态行:协议/版本 状态码 描述
- 响应头:(Response Header)
- 响应正文:
手写服务器
- 获取请求协议
- 创建ServerSocket
- 建立连接获取Socket
- 通过输入流获取请求协议
- 注意:GET和POST不一致的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| package com.zhuchuli.server;
import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;
public class Server01 { private ServerSocket serverSocket; public static void main(String[] args) { Server01 server=new Server01(); server.start(); server.receive(); } public void start() { try { serverSocket=new ServerSocket(8888); } catch (IOException e) { System.out.println("服务器启动失败..."); e.printStackTrace(); } } public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接...."); InputStream is=client.getInputStream(); byte[] datas=new byte[1024*1024]; int len=is.read(datas); String requestInfo = new String(datas,0,len); System.out.println(requestInfo); } catch (Exception e) { System.out.println("客户端连接出现错误..."); } } public void stop() { } }
|
- 返回响应协议
- 准备内容。
- 获取字节数的长度。
- 拼接响应协议。
- 使用输出流输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| package com.zhuchuli.server;
import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date;
public class Server02 { private ServerSocket serverSocket; public static void main(String[] args) { Server02 server=new Server02(); server.start(); } public void start() { try { serverSocket=new ServerSocket(8888); receive(); } catch (IOException e) { System.out.println("服务器启动失败..."); e.printStackTrace(); } } public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接...."); InputStream is=client.getInputStream(); byte[] datas=new byte[1024*1024]; int len=is.read(datas); String requestInfo = new String(datas,0,len); System.out.println(requestInfo); StringBuilder content=new StringBuilder(); content.append("<html>"); content.append("<head>"); content.append("<title>"); content.append("服务器响应成功"); content.append("</title>"); content.append("</head>"); content.append("<body>"); content.append("zhuchuli Server回来了..."); content.append("</body>"); content.append("</html>"); int size= content.toString().getBytes().length; StringBuilder responseInfo=new StringBuilder(); String blank=" "; String CRLF="\r\n"; responseInfo.append("HTTP/1.1").append(blank); responseInfo.append(200).append(blank); responseInfo.append("OK").append(CRLF);
responseInfo.append("Date:").append(new Date()).append(CRLF); responseInfo.append("Server:").append("zhuchuli Server/0.0.1;charset=GBK").append(CRLF); responseInfo.append("Content-Type:text/html").append(CRLF); responseInfo.append("Content-Length:").append(size).append(CRLF); responseInfo.append(CRLF); responseInfo.append(content.toString()); BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"UTF-8")); bw.write(responseInfo.toString()); bw.flush(); } catch (Exception e) { System.out.println("客户端连接出现错误..."); } } public void stop() { } }
|
- 封装响应信息
- 动态添加内容print;
- 累加字节数的长度;
- 根据状态码拼接响应头协议;
- 根据状态码同意推送出去;
- 调用处:动态调用print + 传入状态码推送。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| package com.zhuchuli.server;
import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.util.Date;
public class Response { private BufferedWriter bw; private StringBuilder content; private StringBuilder headInfo; private final String BLANK=" "; private final String CRLF="\r\n"; private int len; private Response() { content=new StringBuilder(); headInfo=new StringBuilder(); len=0; } public Response(Socket client) { this(); try { bw=new BufferedWriter(new OutputStreamWriter(client.getOutputStream(),"UTF-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); headInfo=null; } catch (IOException e) { e.printStackTrace(); 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; } public void pushToBrower(int code) throws IOException { if(null == headInfo) { code=505; } createHeadInfo(code); bw.append(headInfo); bw.append(content); bw.flush(); } private void createHeadInfo(int code) { headInfo.append("HTTP/1.1").append(BLANK); headInfo.append(code).append(BLANK); switch(code) { case 200: headInfo.append("OK").append(CRLF); break; case 404: headInfo.append("NOT FOUND").append(CRLF); break; case 505: headInfo.append("SERVER ERROR").append(CRLF); break; }
headInfo.append("Date:").append(new Date()).append(CRLF); headInfo.append("Server:").append("zhuchuli Server/0.0.1;charset=GBK").append(CRLF); headInfo.append("Content-Type:text/html").append(CRLF); headInfo.append("Content-Length:").append(len).append(CRLF); headInfo.append(CRLF); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| package com.zhuchuli.server;
import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date;
public class Server03 { private ServerSocket serverSocket; public static void main(String[] args) { Server03 server=new Server03(); server.start(); } public void start() { try { serverSocket=new ServerSocket(8888); receive(); } catch (IOException e) { System.out.println("服务器启动失败..."); e.printStackTrace(); } } public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接...."); InputStream is=client.getInputStream(); byte[] datas=new byte[1024*1024]; int len=is.read(datas); String requestInfo = new String(datas,0,len); System.out.println(requestInfo); Response response=new Response(client); response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("服务器响应成功"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("zhuchuli Server回来了..."); response.print("</body>"); response.print("</html>"); response.pushToBrower(200); } catch (Exception e) { System.out.println("客户端连接出现错误..."); } } public void stop() { } }
|
- 封装请求信息
- 通过分解字符串获取method、url和请求参数
Post请求参数可能在请求体中存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| package com.zhuchuli.server;
import java.io.IOException; import java.io.InputStream; import java.net.Socket;
public class Request { private String requestInfo; private String method; private String url; private String queryStr; private final String CRLF="\r\n"; public Request(Socket client) throws IOException { this(client.getInputStream()); } public Request(InputStream is) { byte[] datas=new byte[1024*1024]; int len; try { len = is.read(datas); this.requestInfo = new String(datas,0,len); System.out.println(requestInfo); } catch (Exception e) { return; } parseRequestInfo(); } private void parseRequestInfo() { System.out.println("-------分解---------"); System.out.println("------1、获取请求方式:开头到第一个/----------"); this.method=this.requestInfo.substring(0, this.requestInfo.indexOf("/")-1).toLowerCase(); System.out.println("------2、获取请求URL:第一个/到HTTP/----------"); System.out.println("---------可能包含请求参+数?前面的为url------------"); int startIdx=this.requestInfo.indexOf("/")+1; int endIdx=this.requestInfo.indexOf("HTTP/"); this.url=this.requestInfo.substring(startIdx,endIdx); int queryIdx=this.url.indexOf("?"); if(queryIdx >= 0) { String[] urlArray=this.url.split("\\?"); this.url=urlArray[0]; this.queryStr=urlArray[1].trim(); } System.out.println("------3、获取请求URL后面的请求参数GET已经获取,如果是Post可能在请求体中----------"); if(method.equals("post")) { String qStr= this.requestInfo.substring(this.requestInfo.lastIndexOf(CRLF)).trim(); if(null== queryStr) { queryStr=qStr; }else { queryStr += "&"+qStr; } } queryStr = null == queryStr?"":queryStr; System.out.println(method+"---->"+url+"---->"+this.queryStr); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| package com.zhuchuli.server;
import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date;
public class Server04 { private ServerSocket serverSocket; public static void main(String[] args) { Server04 server=new Server04(); server.start(); } public void start() { try { serverSocket=new ServerSocket(8888); receive(); } catch (IOException e) { System.out.println("服务器启动失败..."); e.printStackTrace(); } } public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接...."); Request request=new Request(client); Response response=new Response(client); response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("服务器响应成功"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("zhuchuli Server回来了..."); response.print("</body>"); response.print("</html>"); response.pushToBrower(200); } catch (Exception e) { System.out.println("客户端连接出现错误..."); } } public void stop() { } }
|
- 处理请求参数
- 通过Map封装请求参数两个方法:
getParameter(String key),getParameterValues(String key);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
| package com.zhuchuli.server;
import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map;
public class Request02 { private String requestInfo; private String method; private String url; private String queryStr; private Map<String,List<String>> parameterMap; private final String CRLF="\r\n"; public Request02(Socket client) throws IOException { this(client.getInputStream()); } public Request02(InputStream is) { parameterMap = new HashMap<String, List<String>>(); byte[] datas=new byte[1024*1024]; int len; try { len = is.read(datas); this.requestInfo = new String(datas,0,len); System.out.println(requestInfo); } catch (Exception e) { return; } parseRequestInfo(); } private void parseRequestInfo() { System.out.println("-------分解---------"); System.out.println("------1、获取请求方式:开头到第一个/----------"); this.method=this.requestInfo.substring(0, this.requestInfo.indexOf("/")-1).toLowerCase(); System.out.println("------2、获取请求URL:第一个/到HTTP/----------"); System.out.println("---------可能包含请求参+数?前面的为url------------"); int startIdx=this.requestInfo.indexOf("/")+1; int endIdx=this.requestInfo.indexOf("HTTP/"); this.url=this.requestInfo.substring(startIdx,endIdx); int queryIdx=this.url.indexOf("?"); if(queryIdx >= 0) { String[] urlArray=this.url.split("\\?"); this.url=urlArray[0]; this.queryStr=urlArray[1].trim(); } System.out.println("------3、获取请求URL后面的请求参数GET已经获取,如果是Post可能在请求体中----------"); if(method.equals("post")) { String qStr= this.requestInfo.substring(this.requestInfo.lastIndexOf(CRLF)).trim(); if(null== queryStr) { queryStr=qStr; }else { queryStr += "&"+qStr; } } queryStr = null == queryStr?"":queryStr; System.out.println(method+"---->"+url+"---->"+this.queryStr); convertMap(); } private void convertMap() { String[] keyValues= this.queryStr.split("&"); for(String keyValue:keyValues) { String[] kv=keyValue.split("="); kv = Arrays.copyOf(kv, 2); String key=kv[0]; String value=kv[1] == null?null:decode(kv[1],"UTF-8"); if(!parameterMap.containsKey(key)) { parameterMap.put(key,new ArrayList<String>()); } parameterMap.get(key).add(value); } }
private String decode(String value,String enc) { try { return java.net.URLDecoder.decode(value,enc); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } }
public String[] getParameterValues(String key) { List<String> list=this.parameterMap.get(key); if(null == list || list.size()<1) { return null; } return list.toArray(new String[0]); }
public String getParameter(String key) { String[] values=getParameterValues(key); return values == null?null:values[0]; } public String getMethod() { return method; } public String getUrl() { return url; } public String getQueryStr() { return queryStr; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| package com.zhuchuli.server;
import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date;
public class Server05 { private ServerSocket serverSocket; public static void main(String[] args) { Server05 server=new Server05(); server.start(); } public void start() { try { serverSocket=new ServerSocket(8888); receive(); } catch (IOException e) { System.out.println("服务器启动失败..."); e.printStackTrace(); } } public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接...."); Request02 request=new Request02(client); Response response=new Response(client); response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("服务器响应成功"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("zhuchuli Server回来了..."+request.getParameter("uname")); response.print("</body>"); response.print("</html>"); response.pushToBrower(200); } catch (Exception e) { System.out.println("客户端连接出现错误..."); } } public void stop() { } }
|
- 引入Servlet
- 将业务代码解耦到对应的业务类中(具体的Servlet)
- 例子:Request与Response与上面雷同。
1 2 3 4 5 6 7 8 9
| package com.zhuchuli.server;
public interface Servlet { void service(Request request,Response response); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.zhuchuli.server;
public class RegisterServlet implements Servlet{
@Override public void service(Request request,Response response) { response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("第一个Servlet"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("注册成功:"+request.getParameter("uname")); response.print("</body>"); response.print("</html>"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.zhuchuli.server;
public class LoginServlet implements Servlet{
@Override public void service(Request request,Response response) { response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("第一个Servlet"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("欢迎回来:"+request.getParameter("uname")); response.print("</body>"); response.print("</html>"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| package com.zhuchuli.server;
import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date;
public class Server06 { private ServerSocket serverSocket; public static void main(String[] args) { Server06 server=new Server06(); server.start(); } public void start() { try { serverSocket=new ServerSocket(8888); receive(); } catch (IOException e) { System.out.println("服务器启动失败..."); e.printStackTrace(); } } public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接...."); Request request=new Request(client); Response response=new Response(client); if(request.getUrl().equals("login")) { Servlet servlet=new LoginServlet(); servlet.service(request, response); }else if(request.getUrl().equals("reg")){ Servlet servlet=new RegisterServlet(); servlet.service(request, response); } response.pushToBrower(200); } catch (Exception e) { System.out.println("客户端连接出现错误..."); } } public void stop() { } }
|
- 整合web.xml
- 根据配置文件动态的读取类名,再进行反射获取具体的Servlet来处理业务,真正的以不变应万变。
- 例子:Request类、Response类、Servlet接口、LoginServlet类、RegisterServlet类与上面雷同;web.xml配置文件暂时存放在src下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| package com.zhuchuli.server;
import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date;
public class Server07 { private ServerSocket serverSocket; public static void main(String[] args) { Server07 server=new Server07(); server.start(); } public void start() { try { serverSocket=new ServerSocket(8888); receive(); } catch (IOException e) { System.out.println("服务器启动失败..."); e.printStackTrace(); } } public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接...."); Request request=new Request(client); Response response=new Response(client); Servlet servlet=WebApp.getServletFromUrl(request.getUrl()); System.out.println(servlet+"--->"+servlet); if(null!=servlet) { servlet.service(request, response); response.pushToBrower(200); }else { response.pushToBrower(404); } } catch (Exception e) { System.out.println("客户端连接出现错误..."); } } public void stop() { } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| package com.zhuchuli.server;
import java.util.ArrayList; import java.util.List;
import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler;
public class WebApp { private static WebContext webContext; static { try { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); WebHandler handler = new WebHandler(); parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("web.xml"), handler); webContext=new WebContext(handler.getEntitys(), handler.getMappings()); }catch(Exception e) { System.out.println("解析配置文件错误"); } }
public static Servlet getServletFromUrl(String url) { String className = webContext.getClz("/" + url); Class clz; try { clz = Class.forName(className); Servlet servlet=(Servlet) clz.getConstructor().newInstance(); return servlet; } catch (Exception e) { e.printStackTrace(); } return null; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| package com.zhuchuli.server;
import java.util.ArrayList; import java.util.List;
import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler;
public class WebHandler extends DefaultHandler{ private List<Entity> entitys; private List<Mapping> mappings; private Entity enity; private Mapping mapping; private String tag; private boolean isMapping = false; @Override public void startDocument() throws SAXException { entitys=new ArrayList<Entity>(); mappings=new ArrayList<Mapping>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if(null!=qName) { tag=qName; if(tag.equals("servlet")) { enity=new Entity(); isMapping = false; }else if(tag.equals("servlet-mapping")) { mapping=new Mapping(); isMapping = true; } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents=new String(ch,start,length).trim(); if(null != tag) { if(isMapping) { if(tag.equals("servlet-name")) { mapping.setName(contents); }else if(tag.equals("url-pattern")) { mapping.addPatterns(contents); } }else { if(tag.equals("servlet-name")) { enity.setName(contents); }else if(tag.equals("servlet-class")) { enity.setClz(contents); } } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if(null!=qName) { if(qName.equals("servlet")) { entitys.add(enity); }else if(qName.equals("servlet-mapping")) { mappings.add(mapping); } } tag=null; } @Override public void endDocument() throws SAXException { } public List<Entity> getEntitys() { return entitys; } public List<Mapping> getMappings() { return mappings; }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package com.zhuchuli.server;
import java.util.HashSet; import java.util.Set;
public class Mapping { private String name; private Set<String> patterns; public Mapping() { patterns = new HashSet<String>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<String> getPatterns() { return patterns; } public void setPatterns(Set<String> patterns) { this.patterns = patterns; } public void addPatterns(String pattern) { this.patterns.add(pattern); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package com.zhuchuli.server;
public class Entity { private String name; private String clz; public Entity() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClz() { return clz; } public void setClz(String clz) { this.clz = clz; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.zhuchuli.server.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> <url-pattern>/g</url-pattern> </servlet-mapping> <servlet> <servlet-name>reg</servlet-name> <servlet-class>com.zhuchuli.server.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>reg</servlet-name> <url-pattern>/reg</url-pattern> <url-pattern>/r</url-pattern> </servlet-mapping> </web-app>
|
- 高效分发器
- 加入了多线程,可以同时处理多个请求,使用的是短链接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| package com.zhuchuli.server;
import java.io.IOException; import java.net.Socket;
public class Dispatcher implements Runnable{ private Socket client; private Request request; private Response response; public Dispatcher(Socket client) { this.client=client; try { request=new Request(client); response=new Response(client); } catch (IOException e) { e.printStackTrace(); this.release(); } } @Override public void run() { try { Servlet servlet=WebApp.getServletFromUrl(request.getUrl()); if(null!=servlet) { servlet.service(request, response); response.pushToBrower(200); }else { response.pushToBrower(404); } }catch(Exception e) { try { response.pushToBrower(505); } catch (IOException e1) { e1.printStackTrace(); } } release(); } private void release() { try { client.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package com.zhuchuli.server;
import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date;
public class Server08 { private ServerSocket serverSocket; private boolean isRunning; public static void main(String[] args) { Server08 server=new Server08(); server.start(); } public void start() { try { serverSocket=new ServerSocket(8888); isRunning = true; receive(); } catch (IOException e) { System.out.println("服务器启动失败..."); stop(); e.printStackTrace(); } } public void receive() { while(isRunning) { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接...."); new Thread(new Dispatcher(client)).start(); } catch (Exception e) { System.out.println("客户端连接出现错误..."); } } } public void stop() { isRunning=false; try { this.serverSocket.close(); System.out.println("服务器已经停止"); } catch (IOException e) { e.printStackTrace(); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| package com.zhuchuli.server;
import java.io.IOException; import java.io.InputStream; import java.net.Socket;
public class Dispatcher2 implements Runnable{ private Socket client; private Request request; private Response response; public Dispatcher2(Socket client) { this.client=client; try { request=new Request(client); response=new Response(client); } catch (IOException e) { e.printStackTrace(); this.release(); } } @Override public void run() { try { if(null==request.getUrl() || request.getUrl().equals("")) { InputStream is=Thread.currentThread().getContextClassLoader().getResourceAsStream("index.html"); response.print(new String(is.readAllBytes(),"utf-8")); response.pushToBrower(200); is.close(); return; } Servlet servlet=WebApp.getServletFromUrl(request.getUrl()); if(null!=servlet) { servlet.service(request, response); response.pushToBrower(200); }else { InputStream is=Thread.currentThread().getContextClassLoader().getResourceAsStream("error.html"); response.print(new String(is.readAllBytes(),"utf-8")); response.pushToBrower(404); is.close(); } }catch(Exception e) { try { response.pushToBrower(505); } catch (IOException e1) { e1.printStackTrace(); } } release(); } private void release() { try { client.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
|
—> 还差中文乱码有待解决 <—-
内容到这里暂时就结束了