• 【Linux从0到1】第十四篇:HTTP&&HTTPS



    一、网络版计算器

    约定方案一:

    • 客户端发送一个形如"1+1"的字符串;
    • 这个字符串中有两个操作数, 都是整形;
    • 两个数字之间会有一个字符是运算符, 运算符只能是 + ;
    • 数字和运算符之间没有空格

    约定方案二:

    • 定义结构体来表示我们需要交互的信息;
    • 发送数据时将这个结构体按照一个规则转换成字符串, 接收到数据的时候再按照相同的规则把字符串转化回结构体;
    • 这个过程叫做 “序列化” 和 “反序列化”

    Protocol.hpp

    #pragma once
    #include 
    #include 
    
    // 定制协议的过程,目前就是定制结构化数据的过程
    // 请求格式
    // 我们自己定义的协议,client && server 都必须遵守! 这就叫做自定义协议
    typedef struct Request
    {
        int _x;
        int _y;
        char _op;   // "+-*/%"
    }request_t;
    
    typedef struct Response
    {
        int code; /// server运算完毕的计算状态: code(0:success), code(-1: div 0) ...
        int _result; // 计算结果
    }response_t;
    
    // 序列化过程
    std::string serializationRequest(request_t& req)
    {
        Json::Value root;
        root["datax"] = req._x;
        root["datay"] = req._y;
        root["operator"] = req._op;
    
        Json::FastWriter writer;
        std::string json_string = writer.write(root);
        return json_string;
    }
    
    //反序列化
    void DeserializationRequest(const std::string& json_string, request_t& out)
    {
        Json::Reader reader;
        Json::Value root;
        reader.parse(json_string, root);
        out._x = root["datax"].asInt();
        out._y = root["datay"].asInt();
        out._op = (char)root["operator"].asUInt();
    }
    
    std::string serializationResponse(response_t& resp)
    {
        Json::Value root;
        root["code"] = resp.code;
        root["result"] = resp._result;
        Json::FastWriter writer;
        std::string json_string = writer.write(root);
        return json_string;
    }
    
    void DeserializationResponse(const std::string& json_string, response_t& out)
    {
        Json::Reader reader;
        Json::Value root;
        reader.parse(json_string, root);
        out.code = root["code"].asInt();
        out._result = root["result"].asInt();
    }
    
    • 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

    sock.hpp

    #pragma once
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    class Sock
    {
    public:
        static int Socket()
        {
            int sock = socket(AF_INET, SOCK_STREAM, 0);
            if(sock < 0)
            {
                std::cerr << "Socket error" << errno << std::endl;
                exit(2);
            }
            return sock;
        }
    
        static void Bind(int sock, u_int16_t port)
        {
            struct sockaddr_in local;
            local.sin_family = AF_INET;
            local.sin_addr.s_addr = INADDR_ANY;
            local.sin_port = htons(port);
    
            if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
            {
                std::cerr << "Bind error" << errno << std::endl;
                exit(3);
            }
        }
    
        static void Listen(int sock)
        {
            if(listen(sock, 5) < 0)
            {
                std::cerr << "Listen error" << errno << std::endl;
                exit(4);
            }
        }
    
        static int Accept(int sock)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int fd = accept(sock, (struct sockaddr*)&peer, &len);
            if(fd >= 0)
            {
                return fd;
            }
            return -1;
        }
    
        static void Connect(int sock, std::string server_ip, uint16_t port)
        {
            struct sockaddr_in peer;
            memset(&peer, 0, sizeof(sockaddr_in));
            peer.sin_family = AF_INET;
            peer.sin_addr.s_addr = inet_addr(server_ip.c_str());
            peer.sin_port = htons(port);
            
            if(connect(sock, (struct sockaddr*)&peer, sizeof(peer)) < 0)
            {
                std::cerr << "connet failed" << errno << std::endl;
                exit(5);
            }
        }
    };
    
    
    • 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

    cal_client.cc

    #include "Protocol.hpp"
    #include "Sock.hpp"
    #include 
    #include 
    
    void Usage(std::string proc)
    {
        std::cout << "Usage:\n\t" << proc << " server_ip server_port" << std::endl;
    }
    
    int main(int argc, char *argv[])
    {
        if (argc != 3)
        {
            Usage(argv[0]);
            return 1;
        }
    
        std::string ip = argv[1];
        uint16_t port = static_cast<uint16_t>(atoi(argv[2]));
        int sock = Sock::Socket();
        Sock::Connect(sock, ip, port);
        std::cout << "connect success!" << std::endl;
    
        request_t req;
        std::cout << "please input data one#" << std::endl;
        std::cin >> req._x;
        std::cout << "please input data two#" << std::endl;
        std::cin >> req._y;
        std::cout << "please input operator#" << std::endl;
        std::cin >> req._op;
        // 序列化
        std::string json_string = serializationRequest(req);
        write(sock, json_string.c_str(), json_string.size());
        // write(sock, &req, sizeof(req));
        char buffer[1024];
        ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
        if (s > 0)
        {
            buffer[s] = 0;
            response_t resp;
            std::string str = buffer;
            DeserializationResponse(str, resp);
            std::cout << "code[0:success]:" << resp.code << std::endl;
            std::cout << "result:" << resp._result << std::endl;
        }
    
        // response_t resp;
        // memset(&resp, 0, sizeof(resp));
    
        // read(sock, &resp, sizeof(resp));
    
        // std::cout << "code[0:success]:" << resp.code << std::endl;
        // std::cout << "result:" << resp._result << std::endl;
        return 0;
    }
    
    • 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

    cal_server.cc

    #include "Protocol.hpp"
    #include "Sock.hpp"
    #include 
    #include 
    #include 
    
    void Usage(std::string proc)
    {
        std::cout << "Usage:\n\t" << proc << " server_port" << std::endl;
    }
    
    void HandlerRequest(int *args)
    {
        int sock = *args;
        delete args;
        //业务逻辑, 做一个短服务 request-> 分析处理->构建response-> sent(response) -> colse(sock)
        // 1. 读取请求
        request_t req;
        char buffer[1024];
        ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
        if(s > 0)
        {
            buffer[s] = 0;
            std::string str = buffer;
            DeserializationRequest(str, req);
    
        //ssize_t s = read(sock, &req, sizeof(req));
        // if (s == sizeof(req))
        // {
            // 分析请求 && 计算结果
            response_t resp = {0, 0};
    
            switch (req._op)
            {
            case '+':
                resp._result = req._x + req._y;
                break;
            case '-':
                resp._result = req._x - req._y;
                break;
            case '*':
                resp._result = req._x * req._y;
                break;
            case '/':
                if (req._y == 0) // code = -1 除0错误
                {
                    resp.code = -1;
                }
                else
                {
                    resp._result = req._x / req._y;
                }
                break;
            case '%':
                if (req._y == 0) // code = -2 模0错误
                {
                    resp.code = -2;
                }
                else
                {
                    resp._result = req._x % req._y;
                }
                break;
            default: // code = -3 请求方法异常
                resp.code = -3;
                break;
            }
            // 构建链接,并且返回
            std::string json_str = serializationResponse(resp);
            write(sock, json_str.c_str(), json_str.size());
            // write(sock, &resp, sizeof(resp));
            std::cout << "服务结束!" << std::endl;
        // }
        }
        // 关闭套接字
        close(sock);
    }
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            Usage(argv[0]);
            return 1;
        }
        u_int16_t port = static_cast<u_int16_t>(atoi(argv[1]));
        int listen_sock = Sock::Socket();
        Sock::Bind(listen_sock, port);
        Sock::Listen(listen_sock);
    
        for (;;)
        {
            int new_sock = Sock::Accept(listen_sock);
            if (new_sock >= 0)
            {
                int *pram = new int(new_sock);
                std::thread t(HandlerRequest, pram);
                t.detach();
            }
        }
        return 0;
    }
    
    • 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

    无论我们采用方案一, 还是方案二, 还是其他的方案, 只要保证, 一端发送时构造的数据, 在另一端能够正确的进行解析, 就是ok的. 这种约定, 就是 应用层协议

    二、HTTP协议

    虽然我们说, 应用层协议是我们程序猿自己定的.
    但实际上, 已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用. HTTP(超文本传输协议)就是其中之一

    2.1 认识URL

    平时我们俗称的 “网址” 其实就是说的 URL
    在这里插入图片描述
    urlencode和urldecode

    像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
    比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义

    转义的规则如下:
    将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式
    在这里插入图片描述
    “+” 被转义成了 “%2B”
    urldecode就是urlencode的逆过程;

    urldecode解码工具

    2.2 HTTP协议格式

    在这里插入图片描述
    Sock.hpp

    #pragma once
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    class Sock
    {
    public:
        static int Socket()
        {
            int sock = socket(AF_INET, SOCK_STREAM, 0);
            if(sock < 0)
            {
                std::cerr << "Socket error" << errno << std::endl;
                exit(2);
            }
            return sock;
        }
    
        static void Bind(int sock, u_int16_t port)
        {
            struct sockaddr_in local;
            local.sin_family = AF_INET;
            local.sin_addr.s_addr = INADDR_ANY;
            local.sin_port = htons(port);
    
            if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
            {
                std::cerr << "Bind error" << errno << std::endl;
                exit(3);
            }
        }
    
        static void Listen(int sock)
        {
            if(listen(sock, 5) < 0)
            {
                std::cerr << "Listen error" << errno << std::endl;
                exit(4);
            }
        }
    
        static int Accept(int sock)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int fd = accept(sock, (struct sockaddr*)&peer, &len);
            if(fd >= 0)
            {
                return fd;
            }
            return -1;
        }
    
        static void Connect(int sock, std::string server_ip, uint16_t port)
        {
            struct sockaddr_in peer;
            memset(&peer, 0, sizeof(sockaddr_in));
            peer.sin_family = AF_INET;
            peer.sin_addr.s_addr = inet_addr(server_ip.c_str());
            peer.sin_port = htons(port);
            
            if(connect(sock, (struct sockaddr*)&peer, sizeof(peer)) < 0)
            {
                std::cerr << "connet failed" << errno << std::endl;
                exit(5);
            }
        }
    };
    
    
    • 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

    Http.cc

    #include "Sock.hpp"
    #include 
    #include 
    #include 
    
    void Usage(std::string proc)
    {
        std::cout << "Usage\n\t" << proc << " prot" << std::endl;
    }
    
    void Handler(int *pSock)
    {
        int sock = *pSock;
        delete pSock;
    #define MAX_SIZE 1024 * 10
        char buffer[MAX_SIZE];
        memset(buffer, 0, sizeof(buffer));
    
        ssize_t s = recv(sock, buffer, sizeof(buffer), 0);
        if (s > 0)
        {
            buffer[s] = 0;
            std::cout << buffer;
    
            std::string ret = "http/1.0 200 OK\n";
            ret += "Content-Type: text/plain\n"; //text/plain,正文是普通的文本
            ret += "\n";
            ret += "hello world";
    
            send(sock, ret.c_str(), ret.size(), 0);
        }
        close(sock);
    }
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            Usage(argv[0]);
            return 1;
        }
    
        uint16_t port = static_cast<uint16_t>(atoi(argv[1]));
        int listen_sock = Sock::Socket();
        Sock::Bind(listen_sock, port);
        Sock::Listen(listen_sock);
    
        //服务
        for (;;)
        {
            int new_sock = Sock::Accept(listen_sock);
            if (new_sock > 0)
            {
                int *pnew_sock = new int(new_sock);
                std::thread t(Handler, pnew_sock);
                t.detach();
            }
        }
        return 0;
    }
    
    • 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

    在这里插入图片描述
    在这里插入图片描述

    HTTP请求
    在这里插入图片描述

    • 首行: [方法] + [url] + [版本]
    • Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束
    • Body: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度;

    HTTP响应
    在这里插入图片描述

    • 首行: [版本号] + [状态码] + [状态码解释]
    • Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束
    • Body: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度; 如果服务器返回了一个html页面, 那么html页面内容就是在body中.

    2.3 HTTP的方法

    在这里插入图片描述
    其中最常用的就是GET方法和POST方法
    在这里插入图片描述
    Http.cc

    #include "Sock.hpp"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    // wwwwroot下就是web根目录,wwwroot目录下放置的内容,都叫做资源
    // wwwroot 目录下的index.html就叫做网站的首页
    
    #define WWWROOT "./wwwroot/"
    #define HOME_PAGE "index.html"
    
    void Usage(std::string proc)
    {
        std::cout << "Usage\n\t" << proc << " prot" << std::endl;
    }
    
    void Handler(int *pSock)
    {
        int sock = *pSock;
        delete pSock;
    #define MAX_SIZE 1024 * 10
        char buffer[MAX_SIZE];
        memset(buffer, 0, sizeof(buffer));
    
        ssize_t s = recv(sock, buffer, sizeof(buffer), 0);
        if (s > 0)
        {
            buffer[s] = 0;
            std::cout << buffer;
    
        //     std::string ret = "http/1.0 200 OK\n";
        //     ret += "Content-Type: text/plain\n"; //text/plain,正文是普通的文本
        //     ret += "\n";
        //     ret += "hello world";
    
        //     send(sock, ret.c_str(), ret.size(), 0);
            std::string html_file = WWWROOT;
            html_file += HOME_PAGE;
            // 返回的时候不仅仅返回正文网页信息,还要包括http的请求
            std::string http_response = "http/1.0 200 OK\n";
            http_response += "Content-type: text/html; charset=utf-8\n";
            http_response += "Content-Lengt: ";
            struct stat st;
            stat(html_file.c_str(), &st);
            http_response += std::to_string(st.st_size);
            http_response += "\n";
            http_response += "\n";
            // 正文
            std::ifstream in(html_file);
            if(!in.is_open())
            {
                std::cerr << "open html_file error" << std::endl;
            }
            else
            {
                std::string content;
                std::string line;
                while(std::getline(in, line))
                {
                    content += line;
                }
                http_response += content;
                in.close();
                send(sock, http_response.c_str(), http_response.size(), 0);
            }
        }
        close(sock);
    }
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            Usage(argv[0]);
            return 1;
        }
    
        uint16_t port = static_cast<uint16_t>(atoi(argv[1]));
        int listen_sock = Sock::Socket();
        Sock::Bind(listen_sock, port);
        Sock::Listen(listen_sock);
    
        //服务
        for (;;)
        {
            int new_sock = Sock::Accept(listen_sock);
            if (new_sock > 0)
            {
                int *pnew_sock = new int(new_sock);
                std::thread t(Handler, pnew_sock);
                t.detach();
            }
        }
        return 0;
    }
    
    • 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

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2.4 HTTP的状态码

    在这里插入图片描述
    最常见的状态码, 比如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)

    • 301:永久重定向
      在这里插入图片描述
      在这里插入图片描述

    在这里插入图片描述

    • 302 or 307 临时重定向
      在这里插入图片描述

    重定向是浏览器给我们提供支持的浏览器必须识别301,302,307
    server告诉浏览器我应该再去哪里;Location:新的地址

    2.5 HTTP常见Header

    • Content-Type: 数据类型(text/html等)
    • Content-Length: Body的长度
    • Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
    • User-Agent: 声明用户的操作系统和浏览器版本信息;
    • referer: 当前页面是从哪个页面跳转过来的;
    • location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
    • Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

    Connection:keep-alive
    在这里插入图片描述
    Cookie
    Cookie,有时也用其复数形式 Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    Session:
    在计算机中,尤其是在网络应用中,称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在Session对象中。有关使用Session 对象的详细信息,请参阅“ASP应用程序”部分的“管理会话”。注意会话状态仅在支持cookie的浏览器中保留。
    在这里插入图片描述

    三、HTTPS

    http理解思路图
    在这里插入图片描述
    假设采取对称加密:
    在这里插入图片描述

    假设采取非对称加密
    在这里插入图片描述
    最终方案:对称加加密+非对称加密

    在这里插入图片描述
    但是这样也会不安全
    在这里插入图片描述
    上面的本质问题是了client无法判断发来的密匙协商报文是不是合法的服务方发来的,所以就会有CA证书机构,来证明这个服务方是合法的。
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    【HMS Core】定位地图服务常见问题,穿戴设备支持、比例尺支持、在非华为手机上逆地理编码的支持?
    【Flink】 FlinkCDC读取Mysql( DataStream 方式)(带完整源码,直接可使用)
    二十三种设计模式:解密职责链模式-购物优惠活动的设计艺术
    【云原生】Kubernetes核心技术(下)
    Vite 脚手架 -- 实现后台
    深度学习实战02-卷积神经网络(CNN)实现服装图像分类
    Netty入门指南之Reactor模型
    Simulink模型加密共享
    python类内置隐式方法全解
    php面试常问面试题
  • 原文地址:https://blog.csdn.net/qq_52809807/article/details/125822978