zoukankan      html  css  js  c++  java
  • 手写服务器(二)

    封装

    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="
    ";
        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="
    ";
        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="
    ";
        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="
    ";
        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() {
            
        }
    }

    效果:

  • 相关阅读:
    Zookeeper 笔记小结
    kafka-Reblance
    kafka笔记
    Dubbo笔记--
    Dubbo 成熟度策略.
    zookeeper watch笔记
    zookeeper 笔记--curator分布式锁
    zookeeper 笔记
    git原理整体理解
    VM options 以及 properties文件的一些理解
  • 原文地址:https://www.cnblogs.com/ssxblog/p/11320062.html
Copyright © 2011-2022 走看看