hooyantsing's Blog

第95次课程_网络线程协议案例

字数统计: 1.6k阅读时长: 8 min
2019/12/28

源辰76班

第95次课程

2019.12.28

内容

网络线程协议案例[廖彦]

1.Tomcat项目案例

Server.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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.yc.http.v2;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    
    //默认路径:127.0.0.1/Untitled-1.html
    public final static String WEBAPPS = "G:/源码库/HTML/多图校园官网";
    
    /**
     * 启动服务器
     * @throws IOException
     */
    public void startup() throws IOException {
        //启动Socket服务器
        ServerSocket server = new ServerSocket(80);
        System.out.println("服务器启动成功:80");
        
        Socket socket;
        //循环接收浏览器请求
        while((socket = server.accept()) != null) {
            final Socket innerSocket = socket;
            //启动多线程,创建处理器处理客户请求
            new Thread() {
                public void run() {
                    Processor p;
                    try {
                        p = new Processor(innerSocket);
                        p.process();
                    } catch (IOException e) {
                        // TODO 自动生成的 catch 块
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    }
    
    /**
     * 停止服务器
     */
    public void shutdown() {
        
    }
    
    public static void main(String[] args) throws IOException {
        new Server().startup();;
    }
}

Processor.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
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
package com.yc.http.v2;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class Processor {
    private Socket socket;
    private InputStream in;
    private OutputStream out;
    
    private static Map<String,HttpServlet> servletMap = new HashMap<>();
    
    static {
        //将Servlet配置到服务器中
        servletMap.put("/hello.do", new HelloServlet());
    }
    
    /**
     * 构造方法
     */
    public Processor(Socket innerSocket) throws IOException {
        this.socket = innerSocket;
        in = socket.getInputStream();
        out = socket.getOutputStream();
    }

    /**
     * 处理方法
     */
    public void process() throws IOException {
        //创建请求对象
        HttpServletRequest request = new HttpServletRequest(in);
        //创建响应响应
        HttpServletResponse response = new HttpServletResponse(request,out);
        
        File file = new File(Server.WEBAPPS + request.getRequestURL());
        
        /**
         * 1.判断当前的请求地址是否是动态请求
         *         判断当前的地址是否在服务器中注册,那么根据地址可以获取到Servlet对象
         * 2.如果是,则使用Servlet的方法处理请求,返回结果。
         * 3.如果不是则当成静态请求处理
         */
        HttpServlet servlet = servletMap.get(request.getRequestURL());
        if(servlet != null) {
            //动态请求
            servlet.service(request, response);
            //默认设置响应结果码
            if(response.getStatus()==0) {
                response.setStatus(200, "OK");
            }
        } else {
            //静态请求
            if(file.exists()) {
                response.setStatus(200, "OK");
            } else {
                response.setStatus(404, "Not Found");
            }
        }
        
        response.commit();
        
        socket.close();
    }
}

HttpServletRequest.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
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
package com.yc.http.v2;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;

public class HttpServletRequest {
    private String method;
    private String requestURI;
    private String protocol;
    private HashMap<String,String> headerMap = new HashMap<>();
    private HashMap<String,String[]> paramMap = new HashMap<>();

    public HttpServletRequest(InputStream in) throws IOException {
        byte[] buffer = new byte[1024];
        int count = in.read(buffer);
        if(count>0) {
            String reqstring = new String(buffer,0,count);
            //显示请求报文
            System.out.println(reqstring);
            //获取请求报文
            String[] lines = reqstring.split("\r\n");
            method = lines[0].split("\\s")[0];
            //获取资源路径
            requestURI = lines[0].split("\\s")[1];
            /**
             * 从URL 解析中解析 解析请求参数    ~?a=100&a=200&b=300&c=&d
             */
            if(requestURI.contains("?")) {
                int index = requestURI.indexOf("?");
                String paramStr = requestURI.substring(index+1);
                String[] params = paramStr.split("&");
                for(String param : params) {
                    String[] nav = param.split("=");
                    addParameter(nav[0],nav.length==1 ? "" : nav[1]);
                }
                //重设置地址
                requestURI = requestURI.substring(0,index);
            }
            protocol = lines[0].split("\\s")[2];
            
            for(int i=1;i<lines.length;i++) {
                if(lines[i].isEmpty()) {
                    break;
                }
                String[] kv = lines[i].split(":\\s");
                headerMap.put(kv[0], kv[1]);
            }
            
            /**
             * 在此处解析 POST 提交的参数
             */
            
            
            System.out.println(headerMap);
        }
    }

    private void addParameter(String name,String value) {
        String[] values = paramMap.get(name);
        if(values==null) {
            paramMap.put(name,new String[] {value});
        }else {
            //数组扩容
            String[] newValues = new String[values.length+1];
            //源数组 源起始 新数组 新数组起始 拷贝长度
            System.arraycopy(values, 0, newValues, 0, values.length);
            newValues[newValues.length-1] = value;
            paramMap.put(name, newValues);
        }
    }
    
    public String getMethod() {
        return method;
    }
    
    public String getProtocol() {
        return protocol;
    }
    
    public String getRequestURL() {
        return requestURI;
    }
    
    public String getHeader(String headerName) {
        return headerMap.get(headerName);
    }
    
    public String getParameter(String parameter) {
        String[] values = paramMap.get(parameter);
        return values == null ? null : values[0];
    }
    
    public String[] getParameterValues(String parameter) {
        return paramMap.get(parameter);
    }
}

HttpServletResponse.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
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
package com.yc.http.v2;

import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map.Entry;

public class HttpServletResponse {
    private HashMap<String,String> headerMap = new HashMap<>();
    private int status;
    private String statusMsg;
    private HttpServletRequest request;
    private OutputStream out;

    public HttpServletResponse(HttpServletRequest request, OutputStream out) {
        this.request = request;
        this.out = out;
    }
    
    public void setHeader(String key,String value) {
        headerMap.put(key, value);
    }
    
    public void setStatus(int status,String statusMsg) {
        this.status = status;
        this.statusMsg = statusMsg;
    }
    
    //提交,根据请求的页面路径,返回页面的内容
    public void commit() throws IOException {
        //响应头行
        out.write(("HTTP/1.1 " + status + " " + statusMsg+"\n").getBytes());
        String contextType = getContextType(request.getRequestURL());
        out.write(("Context-Type: " + contextType + "\n").getBytes());
        
        //遍历map集合,将集合中的键值对输出到头域中
        for(Entry<String,String> e : headerMap.entrySet()) {
            out.write((e.getKey() + ": " + e.getValue() + "\n").getBytes());
        }
        
        //空行 分隔 CRLF
        out.write("\n".getBytes());
        
        File file;
        if(status == 404) {
            file = new File(Server.WEBAPPS + "404.html");
        } else {
            //判断 caw 流中是否有数据
            String data = caw.toString();
            if(data.length()>0) {
                out.write(data.getBytes());
            } else {
                String filepath = Server.WEBAPPS + request.getRequestURL();
                file = new File(filepath);
                FileInputStream fos = new FileInputStream(file);
                byte[] buffer = new byte[1024];
                int count;
                while((count = fos.read(buffer)) > 0) {
                    out.write(buffer, 0, count);
                }
                fos.close();
            }
        }    
    }
    
    private static String getContextType(String srcpath) {
        int beginIndex = srcpath.lastIndexOf(".");
        String suffix = srcpath.substring(beginIndex);
        switch(suffix) {
        case ".css":
            return "text/css";
        case ".js":
            return "application/javascript";
        case ".jpg":
            return "image/jpeg";
        case ".gif":
            return "image/gif";
        case ".png":
            return "image/png";
        }        
        return "text/html";
    }
    
    //临时保存 数据流
    private CharArrayWriter caw = new CharArrayWriter();
    private PrintWriter pw = new PrintWriter(caw);
    public PrintWriter getWriter() {
        return pw;
    }

    public int getStatus() {
        return status;
    }
}

HttpServlet.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
package com.yc.http.v2;
import java.io.IOException;
public class HttpServlet {
    
    protected void  service(HttpServletRequest request,  HttpServletResponse response) throws  IOException{
       switch(request.getMethod()) {
       case "GET":
           doGet(request,response);
           break;
       case "POST":
           doPost(request,response);
           break;
       case "PUT":
           doPut(request,response);
           break;
       case "DELETE":
           doDelete(request,response);
           break;
       }
    }
    
    protected void doGet(HttpServletRequest  request, HttpServletResponse response)  throws IOException {
    }
    protected void doPost(HttpServletRequest  request, HttpServletResponse response)  throws IOException {
    }
    protected void doPut(HttpServletRequest  request, HttpServletResponse response)  throws IOException {
    }
    protected void  doDelete(HttpServletRequest request,  HttpServletResponse response) throws  IOException {
    }
}

HelloServlet.java

说明:servlet样例

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
package com.yc.http.v2;

import java.io.IOException;
import java.io.PrintWriter;

/**
* 定义Servlet的过程
* 1.继承:HttpServlet
* 2.重写:doXXX方法
* 3.配置:URL(注解,web.xml)
*/

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        PrintWriter out = response.getWriter();
        String name = request.getParameter("name");
        out.print("hello " + name + "!");
        
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // TODO 自动生成的方法存根
        doGet(request, response);
    }
}
CATALOG