• webserver(一)


    1. 创建maven项目WebServer2206

    指定字符集和编码

    <properties>
        
        <maven.compiler.target>1.8maven.compiler.target>
        <maven.compiler.source>1.8maven.compiler.source>
        
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
        <maven.compiler.encoding>UTF-8maven.compiler.encoding>
    properties>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    服务端代码如下

    /**
     * WebServer web容器
     * 用于实现Tomcat基本功能
     */
    public class WebServerApplication {
        private ServerSocket serverSocket;
        public WebServerApplication() {
            try {
                System.out.println("启动服务端...");
                serverSocket=new ServerSocket(8088);
                System.out.println("启动完成");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public void start(){
            try {
                System.out.println("等到客户端连接...");
                Socket socket = serverSocket.accept();
                System.out.println("一个客户端已连接");
                ClientHandler handler=new ClientHandler(socket);
                Thread t=new Thread(handler);
                t.start();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            WebServerApplication server=new WebServerApplication();
            server.start();
    
        }
    }
    
    • 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

    2.创建V1

    创建Module子项目
    在这里插入图片描述
    在这里插入图片描述
    然后V1项目的pom.xml变成如下
    在这里插入图片描述

    3.迭代V1创建V2

    需求分析
    HTTP协议要求浏览器连接服务端后应当发送一个请求,因此版本实现读取请求,并输出到控制台来了解请求的格式和内容
    实现:
    由于服务端可以同时接收多客户端的连接,因此与聊天室相同,主线程仅负责客户端的连接,一旦一个客户端
    连接后则启动一个线程来处理。
    1:在com.webserver.core下新建类:ClientHandler(实现Runnable接口),作为线程任务,
    工作是负责与连接的客户端进行HTTP交互
    2.WebServerApplication主线程节后连接后启动ClientHandler这个任务处理客户端交互
    3.在ClientHandler中读取客户端发送过来的内容(请求内容)big打桩输出
    处理客户端的请求

    /**
     * 与客户端完成一次HTTP的交互
     */
    package com.webserver.core;
    public class ClientHandler implements Runnable{
        private Socket socket;
        public ClientHandler(Socket socket){
            this.socket=socket;
        }
        @Override
        public void run() {
            try{
                InputStream is = socket.getInputStream();
    //            http://localhost:8088/index.html
                int d;
                while ((d=is.read())!=-1){//这样可以不止读取文本信息
                    char c=(char)d;
                    System.out.print(c);
                }
    
            } 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

    访问服务端http://localhost:8088/
    打印信息如下
    在这里插入图片描述

    3.迭代V2创建V3

    读取浏览器发来的首行信息

    在这里插入图片描述

    package com.webserver.core;
    /**
     * 与客户端完成一次HTTP的交互
     * 按照HTTP协议请求,与客户端完成一次交互流程为一问一答
     * 因此,这里分为三步完成该工作:
     * 1:解析请求 目的:将浏览器发送的请求内容读取并整理
     * 2:处理请求 目的:根据浏览器的请求进行对应的处理工作
     * 3:发送响应 目的:将服务端的处理结果回馈给浏览器
     */
    public class ClientHandler implements Runnable{
        private Socket socket;
        public ClientHandler(Socket socket){
            this.socket=socket;
        }
        @Override
        public void run() {
            try{
                InputStream is = socket.getInputStream();
    //            http://localhost:8088/index.html
                int d;
                StringBuilder builder=new StringBuilder();
                char cur=' ';
                char pre=' ';
                while ((d=is.read())!=-1){//这样可以不止读取文本信息
                    cur=(char)d;
                    if(cur==10&&pre==13){
                        break;
                    }
                    builder.append(cur);
                    pre=cur;
                }
                String line=builder.toString();
                System.out.println(line.trim());
                //请求行相关信息
                String method;
                String uri;//抽象路径
                String protocol;//协议版本
                String[] data = line.split("\\s");
                method=data[0];
                uri=data[1];
                protocol=data[2];
                System.out.println("method:"+method);
                System.out.println("uri:"+uri);
                System.out.println("protocol:"+protocol);
    
            } 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

    4.迭代V3创建V4

    抽取一次读取一行的方法

    public class ClientHandler implements Runnable{
        private Socket socket;
        public ClientHandler(Socket socket){
            this.socket=socket;
        }
        @Override
        public void run() {
            try{
                String line=readLine();
                System.out.println("请求行:"+line);
    
    
                //请求相关信息
                String method;//请求方式
                String uri;//抽象路径
                String protocol;//协议版本
                String[] data = line.split("\\s");
                method=data[0];
                uri=data[1];
                protocol=data[2];
                System.out.println("method:"+method);
                System.out.println("uri:"+uri);
                System.out.println("protocol:"+protocol);
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //定义一次读取一行的方法
        private String readLine() throws IOException {
            InputStream is = socket.getInputStream();
            int d;
            StringBuilder builder=new StringBuilder();
            char cur=' ';
            char pre=' ';
            while ((d=is.read())!=-1){//这样可以不止读取文本信息
                cur=(char)d;
                if(cur==10&&pre==13){
                    break;
                }
                builder.append(cur);
                pre=cur;
            }
            return builder.toString().trim();
        }
    }
    
    • 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

    获取所有消息头信息
    在这里插入图片描述

    public class ClientHandler implements Runnable{
        private Socket socket;
        public ClientHandler(Socket socket){
            this.socket=socket;
        }
        @Override
        public void run() {
            try{
                String line=readLine();
                System.out.println("请求行:"+line);
    
                //请求相关信息
                String method;//请求方式
                String uri;//抽象路径
                String protocol;//协议版本
                String[] data = line.split("\\s");
                method=data[0];
                uri=data[1];
                protocol=data[2];
                System.out.println("method:"+method);
                System.out.println("uri:"+uri);
                System.out.println("protocol:"+protocol);
                //获取消息头
                while (true){
                    line=readLine();
                    if(line.isEmpty()){//如果单独读取回车+换行,readLine方法会返回空串
                        break;
                    }
                    System.out.println(line);
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //定义一次读取一行的方法
        private String readLine() throws IOException {
            InputStream is = socket.getInputStream();
            int d;
            StringBuilder builder=new StringBuilder();
            char cur=' ';
            char pre=' ';
            while ((d=is.read())!=-1){//这样可以不止读取文本信息
                cur=(char)d;
                if(cur==10&&pre==13){
                    break;
                }
                builder.append(cur);
                pre=cur;
            }
            return builder.toString().trim();
        }
    }
    
    • 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

    用map接收按":"分割的消息头

    public class ClientHandler implements Runnable{
        private Socket socket;
        public ClientHandler(Socket socket){
            this.socket=socket;
        }
        @Override
        public void run() {
            try{
                String line=readLine();
                System.out.println("请求行:"+line);
    
                //请求相关信息
                String method;//请求方式
                String uri;//抽象路径
                String protocol;//协议版本
                String[] data = line.split("\\s");
                method=data[0];
                uri=data[1];
                protocol=data[2];
                System.out.println("method:"+method);
                System.out.println("uri:"+uri);
                System.out.println("protocol:"+protocol);
    
                Map<String,String> headers=new HashMap<>();
                //获取消息头
                while (true){
                    line=readLine();
                    if(line.isEmpty()){//如果单独读取回车+换行,readLine方法会返回空串
                        break;
                    }
                    System.out.println("原消息头:"+line);
                    String[] arrayStr = line.split(":");
                    headers.put(arrayStr[0],arrayStr[1]);
                }
                System.out.println("-----------------------");
                headers.forEach((k,v)-> System.out.println("集合中的消息头:"+k+":"+v));
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //定义一次读取一行的方法
        private String readLine() throws IOException {
            InputStream is = socket.getInputStream();
            int d;
            StringBuilder builder=new StringBuilder();
            char cur=' ';
            char pre=' ';
            while ((d=is.read())!=-1){//这样可以不止读取文本信息
                cur=(char)d;
                if(cur==10&&pre==13){
                    break;
                }
                builder.append(cur);
                pre=cur;
            }
            return builder.toString().trim();
        }
    }
    
    • 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
  • 相关阅读:
    拆解qlib的dataset,使用代码方式加载数据集
    pytorch实现图像的腐蚀和膨胀
    探究eFuse:硬件保障与系统安全的核心
    会议管理系统SSM记录(一)
    40.组合总和 II
    向某文件中逐秒追加带序号输入当前时间 fgets fputs fprintf sprintf
    Leetcode第 368 场周赛
    使用树莓派连接摄像头与实时视频
    promise的基本用法
    06 OpenCV增加图像的对比度
  • 原文地址:https://blog.csdn.net/longgetaotao_06/article/details/126298329