(1) open system interconnect
OSI是Open System Interconnection的缩写,意为开放式系统互联 。OSI是一个开放性的通信系统互连参考模型,他是一个定义得非常好的协议规范。OSI模型有7层结构,每层都可以有几个子层。 OSI的7层从上到下分别是 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 ;其中高层(即7、6、5、4层)定义了应用程序的功能,下面3层(即3、2、1层)主要面向通过网络的端到端的数据流。
各层功能
应用层
表示层
会话层
传输层
分层优点
(2) http协议
一、
HTTP(HyperText Transfer Protocol)是一套计算机通过网络进行通信的规则。计算机专家设计出HTTP,使HTTP客户(如Web浏览器)能够从HTTP服务器(Web服务器)请求信息和服务,HTTP目前协议的版本是1.1.HTTP是一种无状态的协议,无状态是指Web浏览器和Web服务器之间不需要建立持久的连接,这意味着当一个客户端向服务器端发出请求,然后Web服务器返回响应(response),连接就被关闭了,在服务器端不保留连接的有关信息.HTTP遵循请求(Request)/应答(Response)模型。Web浏览器向Web服务器发送请求,Web服务器处理请求并返回适当的应答。所有HTTP连接都被构造成一套请求和应答。
HTTP使用内容类型,是指Web服务器向Web浏览器返回的文件都有与之相关的类型。所有这些类型在MIME Internet邮件协议上模型化,即Web服务器告诉Web浏览器该文件所具有的种类,是HTML文档、GIF格式图像、声音文件还是独立的应用程序。大多数Web浏览器都拥有一系列的可配置的辅助应用程序,它们告诉浏览器应该如何处理Web服务器发送过来的各种内容类型。
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:
GET /index.html?name=123&pwd=5456 HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: en-US,zh-CN;q=0.5
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.2)
Accept-Encoding: gzip, deflate
Host: localhost:8888
Connection: Keep-Alive
POST /index.html HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: en-US,zh-CN;q=0.5
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; InfoPath.2)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost:8888
Content-Length: 17
Connection: Keep-Alive
Cache-Control: no-cache
uname=123&pwd=213&fav=0&fav=1&fav=2
<head>
协议状态代码描述HTTP响应的第一行类似于HTTP请求的第一行,它表示通信所用的协议是HTTP1.1服务器已经成功的处理了客户端发出的请求(200表示成功):
package com.zwj.demo01; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; /** * 创建服务器,并启动 * @author Administrator * */ public class Server { private ServerSocket server; /** * @param args */ public static void main(String[] args) { Server server = new Server(); server.start(); } /** * 启动方法 */ public void start(){ try { server = new ServerSocket(8888); this.receive(); } catch (IOException e) { e.printStackTrace(); } } /** * 接收客户端 */ private void receive(){ try { Socket client =server.accept(); StringBuilder sb =new StringBuilder(); String msg =null; BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream())); while((msg=br.readLine()).length()>0){ sb.append(msg); sb.append(" "); } //接收客户端的请求信息 String requestInfo =sb.toString().trim(); System.out.println(requestInfo); } catch (IOException e) { //e.printStackTrace(); } } /** * 听着服务器 */ public void stop(){ } }
package com.zwj.demo01; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; /** * 创建服务器,并启动 * @author Administrator * */ public class Server2 { private ServerSocket server; /** * @param args */ public static void main(String[] args) { Server2 server = new Server2(); server.start(); } /** * 启动方法 */ public void start(){ try { server = new ServerSocket(8888); this.receive(); } catch (IOException e) { e.printStackTrace(); } } /** * 接收客户端 */ private void receive(){ try { Socket client =server.accept(); byte[] data=new byte[20480]; int len =client.getInputStream().read(data); //接收客户端的请求信息 String requestInfo=new String(data,0,len).trim(); System.out.println(requestInfo); } catch (IOException e) { //e.printStackTrace(); } } /** * 听着服务器 */ public void stop(){ } } /* POST /log HTTP/1.1 Host: localhost:8888 Connection: keep-alive Content-Length: 17 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: null Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,* ;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 uname=123&pwd=123 */
<html> <head> <title>登录</title> </head> <body> <form method="post" action="http://localhost:8888/index.html"> 用户名:<input type="text" name="uname" id="uname"/> 密码:<input type="password" name="pwd" id="pwd"/> <input type="submit" value="登录"/> </form> </body> </html>
带有响应的服务器名称
package com.zwj.demo01; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; /** * 创建服务器,并启动 * * 1、请求 * 2、响应 * @author Administrator * */ public class Server3 { private ServerSocket server; //换行控制符号 public static final String CRLF=" "; public static final String BLANK=" "; /** * @param args */ public static void main(String[] args) { Server3 server = new Server3(); server.start(); } /** * 启动方法 */ public void start(){ try { server = new ServerSocket(8888); this.receive(); } catch (IOException e) { e.printStackTrace(); } } /** * 接收客户端 */ private void receive(){ try { Socket client =server.accept(); byte[] data=new byte[20480]; int len =client.getInputStream().read(data); //接收客户端的请求信息 String requestInfo=new String(data,0,len).trim(); System.out.println(requestInfo); //响应 StringBuilder responseContext =new StringBuilder(); responseContext.append("<html><head><title>HTTP响应示例</title>" + "</head><body>Hello bjsxt!</body></html>"); StringBuilder response =new StringBuilder(); //1) HTTP协议版本、状态代码、描述 response.append("HTTP/1.1").append(BLANK).append("200").append(BLANK).append("OK").append(CRLF); //2) 响应头(Response Head) response.append("Server:bjsxt Server/0.0.1").append(CRLF); response.append("Date:").append(new Date()).append(CRLF); response.append("Content-type:text/html;charset=GBK").append(CRLF); //正文长度 :字节长度 response.append("Content-Length:").append(responseContext.toString().getBytes().length).append(CRLF); //3)正文之前 response.append(CRLF); //4)正文 response.append(responseContext); System.out.println(responseContext); //输出流 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); bw.write(response.toString()); bw.flush(); bw.close(); } catch (IOException e) { } } /** * 听着服务器 */ public void stop(){ } } /* POST /index.html HTTP/1.1 Host: localhost:8888 Connection: keep-alive Content-Length: 22 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: null Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 uname=zhouwuji&pwd=123 <html><head><title>HTTP响应示例</title></head><body>Hello bjsxt!</body></html> */
分离response、server
package com.zwj.demo01; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Date; /** * 封装响应信息 * @author Administrator * */ public class Response { //两个常量 public static final String CRLF=" "; 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) { 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 505: headInfo.append("SEVER ERROR"); break; } headInfo.append(CRLF); //2) 响应头(Response Head) headInfo.append("Server:bjsxt 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-Length:").append(len).append(CRLF); headInfo.append(CRLF); //分隔符 } //推送到客户端 void pushToClient(int code) throws IOException{ if(null==headInfo){ code =500; } createHeadInfo(code); //头信息+分割符 bw.append(headInfo.toString()); //正文 bw.append(content.toString()); bw.flush(); } public void close(){ CloseUtil.closeIO(bw); } }
package com.zwj.demo01; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; /** * 创建服务器,并启动 * * 1、请求 * 2、响应 * @author Administrator * */ public class Server4 { private ServerSocket server; public static final String CRLF=" "; public static final String BLANK=" "; /** * @param args */ public static void main(String[] args) { Server4 server = new Server4(); server.start(); } /** * 启动方法 */ public void start(){ try { server = new ServerSocket(8888); this.receive(); } catch (IOException e) { e.printStackTrace(); } } /** * 接收客户端 */ private void receive(){ try { Socket client =server.accept(); 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.getOutputStream()); rep.println("<html><head><title>HTTP响应示例</title>"); rep.println("</head><body>Hello server!</body></html>"); rep.pushToClient(200); } catch (IOException e) { } } /** * 听着服务器 */ public void stop(){ } }
package com.zwj.demo01; import java.io.Closeable; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.Socket; public class CloseUtil { /** * 关闭IO流 */ /* public static void closeIO(Closeable... io){ for(Closeable temp:io){ try { if (null != temp) { temp.close(); } } catch (Exception e) { } } }*/ /** * 使用泛型方法实现关闭IO流 * @param io */ public static <T extends Closeable> void closeIO(T... io){ for(Closeable temp:io){ try { if (null != temp) { temp.close(); } } catch (Exception e) { } } } public static void closeSocket(ServerSocket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } public static void closeSocket(Socket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } public static void closeSocket(DatagramSocket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } }
package com.zwj.demo01; import java.io.IOException; import java.net.Socket; /** * 一个请求与响应 就一个此对象 * @author Administrator * */ public class Dispatcher implements Runnable{ private Socket client; private Request req; private Response rep; private int code=200; Dispatcher(Socket client){ this.client=client; try { req =new Request(client.getInputStream()); rep =new Response(client.getOutputStream()); } catch (IOException e) { //e.printStackTrace(); code =500; return ; } } @Override public void run() { Servlet serv =new Servlet(); serv.service(req,rep); try { rep.pushToClient(code); //推送到客户端 } catch (IOException e) { //e.printStackTrace(); } try { rep.pushToClient(500); } catch (IOException e) { e.printStackTrace(); } CloseUtil.closeSocket(client); } }
package com.zwj.demo01; 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 * @author Administrator * */ public class Request { //请求方式 private String method; //请求资源 private String url; //请求参数 private Map<String,List<String>> parameterMapValues; //内部 public static final String CRLF=" "; 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 (Exception e) { return ; } //分析请求信息 parseRequestInfo(); } /** * 分析请求信息 */ private void parseRequestInfo(){ if(null==requestInfo ||(requestInfo=requestInfo.trim()).equals("")){ return ; } /** * ===================================== * 从信息的首行分解出 :请求方式 请求路径 请求参数(get可能存在) * 如:GET /index.html?name=123&pwd=5456 HTTP/1.1 * * 如果为post方式,请求参数可能在 最后正文中 * * 思路: * 1)请求方式 :找出第一个/ 截取即可 * 2)请求资源:找出第一个/ HTTP/ * ===================================== */ 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; } } //不存在请求参数 if(paramString.equals("")){ return ; } //2、将请求参数封装到Map中 parseParams(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){ //Arrays.copyOf 扩容 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 获取对应的多个值 * @param args */ 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 获取对应的单个值 * @param args */ public String getParameter(String name){ String[] values =getParameterValues(name); if(null==values){ return null; } return values[0]; } public String getUrl() { return url; } }
package com.zwj.demo01; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Date; /** * 封装响应信息 * @author Administrator * */ public class Response { //两个常量 public static final String CRLF=" "; 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) { 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 505: headInfo.append("SEVER ERROR"); break; } headInfo.append(CRLF); //2) 响应头(Response Head) headInfo.append("Server:bjsxt 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-Length:").append(len).append(CRLF); headInfo.append(CRLF); //分隔符 } //推送到客户端 void pushToClient(int code) throws IOException{ if(null==headInfo){ code =500; } createHeadInfo(code); //头信息+分割符 bw.append(headInfo.toString()); //正文 bw.append(content.toString()); bw.flush(); } public void close(){ CloseUtil.closeIO(bw); } }
package com.zwj.demo01; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * 创建服务器,并启动 * * 1、请求 * 2、响应 * @author Administrator * */ public class Server7 { private ServerSocket server; public static final String CRLF=" "; public static final String BLANK=" "; private boolean isShutDown= false; /** * @param args */ public static void main(String[] args) { Server7 server = new Server7(); server.start(); } /** * 启动方法 */ public void start(){ start(8888); } /** * 指定端口的启动方法 */ public void start(int port){ try { server = new ServerSocket(port); this.receive(); } catch (IOException e) { //e.printStackTrace(); stop(); } } /** * 接收客户端 */ private void receive(){ try { while(!isShutDown){ new Thread(new Dispatcher(server.accept())).start(); } } catch (IOException e) { //e.printStackTrace(); stop(); } } /** * 停止服务器 */ public void stop(){ isShutDown=true; CloseUtil.closeSocket(server); } }
package com.zwj.demo01; public class Servlet { public void service(Request req,Response rep){ rep.println("<html><head><title>HTTP响应示例</title>"); rep.println("</head><body>"); rep.println("欢迎:").println(req.getParameter("uname")).println("回来"); rep.println("</body></html>"); } }
package com.zwj.demo01; import java.io.Closeable; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.Socket; public class CloseUtil { /** * 关闭IO流 */ /* public static void closeIO(Closeable... io){ for(Closeable temp:io){ try { if (null != temp) { temp.close(); } } catch (Exception e) { } } }*/ /** * 使用泛型方法实现关闭IO流 * @param io */ public static <T extends Closeable> void closeIO(T... io){ for(Closeable temp:io){ try { if (null != temp) { temp.close(); } } catch (Exception e) { } } } public static void closeSocket(ServerSocket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } public static void closeSocket(Socket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } public static void closeSocket(DatagramSocket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } }
sax解析xml文件 注:要继承defaulthandle类 里面有5个方法 startdocument() 、startelentment()得到元素名称 、charcter()得到values值、endelement()、enddocument() 解析式一行一行解析,
和dom4j是把xml变成dom树进行解析
package com.bjsxt.xml; import java.io.IOException; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; public class ParseDemo01 { /** * @param args * @throws SAXException * @throws ParserConfigurationException * @throws IOException */ public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { //1、获取解析工厂 SAXParserFactory factory=SAXParserFactory.newInstance(); //2、从解析工厂获取解析器 SAXParser parse =factory.newSAXParser(); //3、加载文档 Document 注册处理器 //4、编写处理器 PersonHandler handler=new PersonHandler(); parse.parse(Thread.currentThread().getContextClassLoader() .getResourceAsStream("com/bjsxt/xml/person.xml") ,handler ); List<Person> persons =handler.getPersons(); for(Person p:persons){ System.out.println(p.getName()+"-->"+p.getAge()); } } }
package com.bjsxt.xml; public class Person { private String name; private int age; public Person() { // TODO Auto-generated constructor stub } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
<?xml version="1.0" encoding="UTF-8" ?> <persons> <person> <name>至尊宝</name> <age>9000</age> </person> <person> <name>白晶晶</name> <age>7000</age> </person> </persons>
package com.bjsxt.xml; import java.util.ArrayList; import java.util.List; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * 存储对象 * @author Administrator * */ public class PersonHandler extends DefaultHandler { private List<Person> persons; private Person person; private String tag;//记录标签名 @Override public void startDocument() throws SAXException { // TODO Auto-generated method stub //System.out.println("处理文档开始"); persons =new ArrayList<Person>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("开始一个元素" +qName); if(null!=qName){ tag=qName; } if(null!=qName &&qName.equals("person")){ person =new Person(); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String str =new String(ch,start,length); if(null!=tag &&tag.equals("name")){ //System.out.println(new String(ch,start,length)); person.setName(str); }else if(null!=tag &&tag.equals("age")){ Integer age = Integer.valueOf(str); person.setAge(age); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { //System.out.println("结束一个元素" +qName); if(qName.equals("person")){ this.persons.add(person); } tag =null; } @Override public void endDocument() throws SAXException { System.out.println("文档处理结束"); } public List<Person> getPersons() { return persons; } public void setPersons(List<Person> persons) { this.persons = persons; } }
简单的服务器最终版本
package com.zwj.server; import java.io.IOException; import java.net.Socket; import com.zwj.servlet.Servlet; import com.zwj.util.CloseUtil; /** * 一个请求与响应 就一个此对象 * @author Administrator * */ public class Dispatcher implements Runnable{ private Socket client; private Request req; private Response rep; private int code=200; Dispatcher(Socket client){ this.client=client; try { req =new Request(client.getInputStream()); rep =new Response(client.getOutputStream()); } catch (IOException e) { //e.printStackTrace(); code =500; return ; } } @Override public void run() { try { Servlet serv =WebApp.getServlet(req.getUrl()); if(null==serv){ this.code=404; //找不到处理 }else{ serv.service(req, rep); } rep.pushToClient(code); //推送到客户端 }catch (Exception e) { e.printStackTrace(); this.code=500; } try { rep.pushToClient(500); } catch (IOException e) { e.printStackTrace(); } req.close(); rep.close(); CloseUtil.closeSocket(client); } }
package com.zwj.server; /* <servlet> <servlet-name>login</servlet-name> <servlet-class>com.bjsxt.server.demo4.LoginServlet</servlet-class> </servlet> */ public class Entity { private String name; private String clz; 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; } }
package com.zwj.server; import java.util.ArrayList; import java.util.List; /* <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/log</url-pattern> </servlet-mapping> */ public class Mapping { private String name; private List<String> urlPattern; public Mapping(){ urlPattern =new ArrayList<String>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getUrlPattern() { return urlPattern; } public void setUrlPattern(List<String> urlPattern) { this.urlPattern = urlPattern; } }
package com.zwj.server; 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; import com.zwj.util.CloseUtil; /** * 封装request * @author Administrator * */ public class Request { //请求方式 private String method; //请求资源 private String url; //请求参数 private Map<String,List<String>> parameterMapValues; //内部 public static final String CRLF=" "; 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 (Exception e) { return ; } //分析请求信息 parseRequestInfo(); } /** * 分析请求信息 */ private void parseRequestInfo(){ if(null==requestInfo ||(requestInfo=requestInfo.trim()).equals("")){ return ; } /** * ===================================== * 从信息的首行分解出 :请求方式 请求路径 请求参数(get可能存在) * 如:GET /index.html?name=123&pwd=5456 HTTP/1.1 * * 如果为post方式,请求参数可能在 最后正文中 * * 思路: * 1)请求方式 :找出第一个/ 截取即可 * 2)请求资源:找出第一个/ HTTP/ * ===================================== */ 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; } } //不存在请求参数 if(paramString.equals("")){ return ; } //2、将请求参数封装到Map中 parseParams(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 获取对应的多个值 * @param args */ 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 获取对应的单个值 * @param args */ public String getParameter(String name){ String[] values =getParameterValues(name); if(null==values){ return null; } return values[0]; } public String getUrl() { return url; } public void close(){ CloseUtil.closeIO(is); } }
package com.zwj.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; import com.zwj.util.CloseUtil; /** * 封装响应信息 * @author Administrator * */ public class Response { //两个常量 public static final String CRLF=" "; 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) { 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 505: headInfo.append("SEVER ERROR"); break; } headInfo.append(CRLF); //2) 响应头(Response Head) headInfo.append("Server:bjsxt 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-Length:").append(len).append(CRLF); headInfo.append(CRLF); //分隔符 } //推送到客户端 void pushToClient(int code) throws IOException{ if(null==headInfo){ code =500; } createHeadInfo(code); //头信息+分割符 bw.append(headInfo.toString()); //正文 bw.append(content.toString()); bw.flush(); } public void close(){ CloseUtil.closeIO(bw); } }
package com.zwj.server; import java.io.IOException; import java.net.ServerSocket; import com.zwj.util.CloseUtil; /** * 创建服务器,并启动 * * 1、请求 * 2、响应 * @author Administrator * java 世界里可以不手写的尽量用配置,能用约定的就不用配置, 约定>配置>手写 */ public class Server { private ServerSocket server; public static final String CRLF=" "; public static final String BLANK=" "; private boolean isShutDown= false; /** * @param args */ public static void main(String[] args) { Server server = new Server(); server.start(); } /** * 启动方法 */ public void start(){ start(8888); } /** * 指定端口的启动方法 */ public void start(int port){ try { server = new ServerSocket(port); this.receive(); } catch (IOException e) { //e.printStackTrace(); stop(); } } /** * 接收客户端 */ private void receive(){ try { while(!isShutDown){ new Thread(new Dispatcher(server.accept())).start(); } } catch (IOException e) { //e.printStackTrace(); stop(); } } /** * 停止服务器 */ public void stop(){ isShutDown=true; CloseUtil.closeSocket(server); } }
package com.zwj.server; import java.util.HashMap; import java.util.Map; /** * 上下文 * @author Administrator * */ public class ServletContext { //为每一个servlet取个别名 // login -->com.bjsxt.server.demo03.LoginServlet private Map<String,String> servlet ; //url -->login // /log -->login // /login -->login private Map<String,String> mapping; ServletContext(){ servlet =new HashMap<String,String>(); mapping =new HashMap<String,String>(); } public Map<String, String> getServlet() { return servlet; } public void setServlet(Map<String, String> servlet) { this.servlet = servlet; } public Map<String, String> getMapping() { return mapping; } public void setMapping(Map<String, String> mapping) { this.mapping = mapping; } }
package com.zwj.server; import java.util.List; import java.util.Map; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import com.zwj.servlet.Servlet; public class WebApp { private static ServletContext contxt; static{ try { //获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); //获取解析器 SAXParser sax = factory.newSAXParser(); //指定xml+处理器 WebHandler web = new WebHandler(); sax.parse(Thread.currentThread().getContextClassLoader() .getResourceAsStream("WEB_INFO/web.xml"), web); //将list 转成Map contxt =new ServletContext(); Map<String,String> servlet =contxt.getServlet(); //servlet-name servlet-class for(Entity entity:web.getEntityList()){ servlet.put(entity.getName(), entity.getClz()); } //url-pattern servlet-name Map<String,String> mapping =contxt.getMapping(); for(Mapping mapp:web.getMappingList()){ List<String> urls =mapp.getUrlPattern(); for(String url:urls ){ mapping.put(url, mapp.getName()); } } } catch (Exception e) { } } public static Servlet getServlet(String url) throws InstantiationException, IllegalAccessException, ClassNotFoundException{ if((null==url)||(url=url.trim()).equals("")){ return null; } //根据字符串(完整路径)创建对象 //return contxt.getServlet().get(contxt.getMapping().get(url)); String name=contxt.getServlet().get(contxt.getMapping().get(url)); return (Servlet)Class.forName(name).newInstance();//确保空构造存在 } }
package com.zwj.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> entityList; private List<Mapping> mappingList; private Entity entity; private Mapping mapping; private String beginTag ; private boolean isMap; @Override public void startDocument() throws SAXException { //文档解析开始 entityList =new ArrayList<Entity>() ; mappingList =new ArrayList<Mapping>() ; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { //开始元素 if(null!=qName){ beginTag=qName; if(qName.equals("servlet")){ isMap=false; entity=new Entity(); }else if(qName.equals("servlet-mapping")){ isMap=true; mapping=new Mapping(); } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { //处理内容 if(null!=beginTag){ String str =new String(ch,start,length); if(isMap ){ if(beginTag.equals("servlet-name")){ mapping.setName(str); }else if(beginTag.equals("url-pattern")){ mapping.getUrlPattern().add(str); } }else{ if(beginTag.equals("servlet-name")){ entity.setName(str); }else if(beginTag.equals("servlet-class")){ entity.setClz(str); } } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { //结束元素 if(null!=qName){ if(qName.equals("servlet")){ entityList.add(entity); }else if(qName.equals("servlet-mapping")){ mappingList.add(mapping); } } beginTag=null; } @Override public void endDocument() throws SAXException { //文档解析结束 } /*public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { //获取解析工厂 SAXParserFactory factory =SAXParserFactory.newInstance(); //获取解析器 SAXParser sax =factory.newSAXParser(); //指定xml+处理器 WebHandler web = new WebHandler(); sax.parse(Thread.currentThread().getContextClassLoader() .getResourceAsStream("com/bjsxt/server/demo4/web.xml") ,web); System.out.println(web.getEntityList()); }*/ public List<Entity> getEntityList() { return entityList; } public void setEntityList(List<Entity> entityList) { this.entityList = entityList; } public List<Mapping> getMappingList() { return mappingList; } public void setMappingList(List<Mapping> mappingList) { this.mappingList = mappingList; } }
package com.zwj.servlet; import com.zwj.server.Request; import com.zwj.server.Response; public class LoginWeb extends Servlet { @Override public void doGet(Request req, Response rep) throws Exception { rep.println("success....."); } @Override public void doPost(Request req, Response rep) throws Exception { // TODO Auto-generated method stub } }
package com.zwj.servlet; import com.zwj.server.Request; import com.zwj.server.Response; /** * 抽象为一个父类 * @author Administrator * */ public abstract class Servlet { public void service(Request req,Response rep) throws Exception{ this.doGet(req,rep); this.doPost(req,rep); } protected abstract void doGet(Request req,Response rep) throws Exception; protected abstract void doPost(Request req,Response rep) throws Exception; }
package com.zwj.util; import java.io.Closeable; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.Socket; public class CloseUtil { /** * 关闭IO流 */ /* public static void closeIO(Closeable... io){ for(Closeable temp:io){ try { if (null != temp) { temp.close(); } } catch (Exception e) { } } }*/ /** * 使用泛型方法实现关闭IO流 * @param io */ public static <T extends Closeable> void closeIO(T... io){ for(Closeable temp:io){ try { if (null != temp) { temp.close(); } } catch (Exception e) { } } } public static void closeSocket(ServerSocket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } public static void closeSocket(Socket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } public static void closeSocket(DatagramSocket socket){ try { if (null != socket) { socket.close(); } } catch (Exception e) { } } }
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.zwj.servlet.LoginWeb</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/g</url-pattern> <url-pattern>/y</url-pattern> </servlet-mapping> </web-app>