linux篇【14】:网络http协议

news2024/11/19 8:35:27

目录

一.HTTP协议

1.认识URL

(1)域名->必须被转化成为IP

(2)URL中可以省略的部分

        ①端口号可缺省

        ②登录信息可以省略

        ③当我们访问自己的服务器时,https可省略,端口号不可省

(3)特定的服务 与 特定端口 的关系

(4)http协议是做什么的?

(5)如果我们client没有获取的时候,资源在网络服务器上

(6)资源文件在Linux服务器上

(7)Linux要如何找到这个文件呢?——通过路径!

2.urlencode和urldecode

二.http协议的请求格式

1.http协议的请求 分为三部分(我们这里以四部分解析)

(1)请求行

(2)请求报头

(3)空行

(4)有效载荷

<5>.请求实例

2.http响应

(1)响应行

(2)请求报头

(3)空行

(4)有效载荷

3.send 写入函数

4.telnet 命令——远程以协议方式登录某服务

(1)telnet请求服务器

(2)百度上请求服务器

三.http协议的响应,初步使用html

1.html

2.响应内容,使用html

 (1)

(2)Content-Length 保证能读取到完整的正文

 (3)把html和服务器工作解耦——readFile 要请求的资源

        ①文件在哪里? ——在请求的请求行中,第二个字段就是你要访问的文件 。

        ②GET /a/b/c.html http/1.0 中的 / 是web目录,不是根目录

四.表单

1.我们的网络行为有两种

2.GET方法

3.POST方法

4.GET Vs POST

5.代码

server.hpp

index.html


一.HTTP协议

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

1.认识URL

平时我们俗称的 "网址" 其实就是说的 URL。
URL:统一资源定位服务(unit resource locate),用于在互联网中定位某种资源

https://www.baidu.com/         https://www.qq.com/

(1)域名->必须被转化成为IP

因为网络通信的本质: socket, IP+ port,所以(服务器地址)域名->必须被转化成为IP;访问网络服务,服务端必须具有port

(2)URL中可以省略的部分

        ①端口号可缺省

使用确定协议的时候,一般显示的时候,会缺省端口号

浏览器访问指定的url的时候,浏览器或app必须给我们自动添加port
浏览器如何得知,url匹配的port是谁呢?——特定的众所周知服务,端口号必须是确定的! !
httpserver—> 80
httpsServer—>443 sshd—> 22
用户自己写的网络服务bind端口的范围:[1024,n];因为前1023个是给httpserver这些服务的

        ②登录信息可以省略

登录信息我们一般放在页面上登录,一般不放在URL中,所以可以省略。 

        ③当我们访问自己的服务器时,https可省略,端口号不可省

当我们访问自己的服务器时,只需要IP+port:120.78.126.148:8080

https可省略,因为默认会选择https协议;登录信息一般放在页面上登录也可以省略;端口号不可省因为服务是我们自己写的,并不是众所周知服务

(3)特定的服务 与 特定端口 的关系

——>警察 与 110;抢救服务 与 120;火警灭火服务 与 119

(4)http协议是做什么的?

答:用于查阅文档,看音视频,这些都是以网页的形式呈现的。网页实际就是一个 .htmI文件
 http用途获取网页资源的,视频,音频等也都是文件!
解释:http是向特定的服务器申请特定的”资源”的,把资源获取到本地(本地可以是浏览器/app/迅雷播放器)进行展示或者某种使用的!

(5)如果我们client没有获取的时候,资源在网络服务器上

就在你的网络服务器(软件)所在的服务器(硬件,计算机)上

(6)资源文件在Linux服务器上

服务器都是Linux系统的,这些资源都是文件,即资源文件在Linux服务器上。要打开资源文件,读取和发送会给客户端——前提:软件服务器,必须先找到这个文件! !

(7)Linux要如何找到这个文件呢?——通过路径!

/ 就是Linux下的路径分隔符!

https://new.qq.com/rain/a720230106A0fRHW00

2.urlencodeurldecode

/ ? : 等这样的字符 , 已经被 url 当做特殊意义理解了 . 因此这些字符不能随意出现 . 比如, 某个参数中需要带有这些特殊字符 , 就必须先对特殊字符进行转义 .
转义的规则如下 :
将需要转码的字符转为 16 进制,然后从右到左,取 4 ( 不足 4 位直接处理 ) ,每 2 位做一位,前面加上 % ,编码成 %XY
格式

二.http协议的请求格式

1.http协议的请求 分为三部分(我们这里以四部分解析)

每行以 \r\n 结尾

(1)请求行

第一部分只有一行叫 请求行:包含了①请求方法 method。②url 一般省略了域名和端口,只有路径。③版本 http/1.1

注意:http协议请求时大小写是忽略的,例如请求行的 GET / HTTP/1.1  和get / http/1.1 都一样  

(2)请求报头

第二部分包含多行内容叫 请求报头:每一行包含很多请求属性,都是KV形式的,例如 Key: value(注意:和value中间有空格

(3)空行

第三部分只有一行叫 空行:因为只包含了一个 \r\n ,用与做分隔符,把报头和有效载荷分离

(4)有效载荷

第四部分只有一行叫 有效载荷:包含了请求正文:①登陆账号和密码。②个人信息/音频/视频等等。
注意:前三部分(请求行,请求报头,空行)都为http协议的报头;有效载荷就是个人信息

<5>.请求实例

我们利用百度向我们的服务器发起一个请求:

然后我们的服务器仅仅把收到的请求打印出来如下:

因为我们这次请求没有请求正文,所以不显示正文。行下面是第二次请求,因为浏览器是多线程请求,会发送多次请求;或者请求失败会继续发送请求,所以我们会受到多次请求。

DEBUG| 16733361461 whb | accept: Invalid argument | 125. 76.203.191[5129],socket fd: 4
125.76.203.191: 5129
GET / HTTP/1.1           
        ——GET:请求方法;/:是请求的资源。HTTP/1.1:(浏览器)版本
Host: 120. 78.126.148: 8080   
        ——要请求哪个主机,这个主机的IP和port
Connection: keep-alive        
        ——链接方式, keep-alive长链接
Cache- Control: max-age=0        
        ——#cache缓存-暂时不管
Upgrade- Insecure- Requests: 1    
        ——#协议升级-暂时不管
User- Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.3
        ——User- Agent浏览器版本
Accept: text/html,application/xhtml+xml,application/ xml;q=0.9,image/avif,image/webp , image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
        ——上面这个是可接受的资源种类
Accept- Encoding: gzip, deflate
        ——可接受的编码方式
Accept-Language: zh-CN, zh;q=0.9
        ——可接受的语言类型

2.http响应

也是每行以 \r\n 结尾

(1)响应

第一部分只有一行叫 响应:包含了①版本 http/1.1。②状态码。(例如404报错,200代表OK)③状态码描述。(例如404对应的“Not Found”描述)

(2)请求报头

第二部分包含多行内容叫 响应报头:每一行包含很多响应属性,都是KV形式的,例如 Key: value(注意:和value中间有空格

(3)空行

第三部分只有一行叫 空行:因为只包含了一个 \r\n ,用与做分隔符,把报头和有效载荷分离

(4)有效载荷

第四部分只有一行叫 有效载荷:包含了响应正文:①htm/css/js/图片视频音频,自定义信息等——资源

http协议构建一个请求,响应

3.send 写入函数

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

把缓冲区buf中的len个长度数据写入 sockfd这个文件中,flags设为0,send和write函数等价

返回值:返回实际写入的字节数,错误返回-1错误码被设置

4.telnet 命令——远程以协议方式登录某服务

我们的服务器的响应内容:

(1)telnet请求服务器

先把./serverTcp 8080把服务器起来,然后telnet 127.0.0.1 8080,再 ctrl+],输入请求 GET / http/1. 0  ,就可以得到服务器的响应信息

(2)百度上请求服务器

IP+端口,就能得到响应

三.http协议的响应,初步使用html

1.html

HTML 教程 | 菜鸟教程 (runoob.com)

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
    <h1>我的第一个标题</h1>
    <p>我的第一个段落。</p>
</body>
</html>

2.响应内容,使用html

示例:

        HTTP/1.0 200 OK\r\n

         Content-Type 标定正文的类型

 (1)

解释下面:

——"HTTP/1.0 200 OK\r\n";        HTTP/1.0 版本,200状态码表示通过,OK状态码描述
——"Content-Type: text/html\r\n" ;    Content-Type内容类型,正文的类型是html文本类型。(text-文本类型)
——"\r\n";                                                       这是空行
——"<html><h1>hello bite</h1></html>\r\n";    正文内容是hello bite,<html>……</html>是html网页的格式,<h1>……</h1>是使正文成为大标题。(可以搜索html教程学习)

 

(2)Content-Length 保证能读取到完整的正文

任何协议的request or response:
报头+有效载荷
 ①http如何保证自己的报头和有效载荷被全部读取呢?
——无论是请求还是响应,读取完整报头:按行读取,直到读取到空行上

 ②你又如何保证 你能读取到完整的正文呢? ?
——报头能读取完毕,请求或者响应属性中”一定”要包含正文的长度!

 response += ("Content-Length: " + std::to_string(html.size()) + "\r\n");

 (3)把html和服务器工作解耦——readFile 要请求的资源

我要把特定的资源放到特定的目录下的文件中

        ①文件在哪里? ——在请求的请求行中,第二个字段就是你要访问的文件 。

例如:请求行:GET /a/b/c.html http/1.0 ,/a/b/c.html就是要访问的文件

        ②GET /a/b/c.html http/1.0 中的 / 是web目录,不是根目录

a前面的 / 不是根目录, web根目录,但可以设置成为根目录

path = "/a/b/index.html";        ——请求的人请求的文件路径
resource = "./wwwroot"; // 我们的web根目录,我们服务器内部给请求的路径自动加上前缀
resource += path; // ——> ./wwwroot/a/b/index.html
 

四.表单

1.我们的网络行为有两种

(1)我想把远端的资源拿到你的本地: GET /index.html http/1.1
(2)我们想把我们的属性字段,提交到远端,
提交到远端的两种方法:GET or POST
在HTTP中GET会以明文方式将我们对应的参数信息,拼接到url中

2.GET方法

在HTTP中GET会以明文方式将我们对应的参数信息,拼接到url中

 

    <form action="/a/b/c.html" method="get">    
——action文件路径; method打开方法
        Username: <input type="text" name="user"><br>
——input type类型;"user"是KV中的K值;<br>是换行
        Password: <input type="password" name="passwd"><br>
——input type类型是password类型;"passwd"是KV中的K值
        <input type="submit" value="Submit">
——input type类型是"submit"类型;"Submit"是KV中的K值
    </form>

3.POST方法

POST方法提交参数,会将参数以明文的方式,拼接到http的正文中来进行提交!

4.GET Vs POST

1. GET通过url传参
2. POST通过正文传参
3. GET方法传参不私密
4. POST方法因为通过正文传参,所以,相对比较私密- -些
5. GET通过url传参,POST通过正文传参,所以- -般- 些比较大的内容都是通过post方式传参的

5.代码

server.hpp

#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <cerrno>
#include <cassert>

#define CRLF "\r\n"
#define SPACE " "
#define SPACE_LEN strlen(SPACE)
#define HOME_PAGE "index.html"
#define ROOT_PATH "wwwroot"

using namespace std;

std::string getPath(std::string http_request)
{
    std::size_t pos = http_request.find(CRLF);
    if(pos == std::string::npos) return "";
    std::string request_line = http_request.substr(0, pos);
    //GET /a/b/c http/1.1
    std::size_t first = request_line.find(SPACE);
    if(pos == std::string::npos) return "";
    std::size_t second = request_line.rfind(SPACE);
    if(pos == std::string::npos) return "";

    std::string path = request_line.substr(first+SPACE_LEN, second - (first+SPACE_LEN));
    if(path.size() == 1 && path[0] == '/') path += HOME_PAGE;   
若客户端请求的只有一个web根目录,web根目录下那么多资源,不可能全给客户。
所以我们需要加上 index.html,让他只能访问到首页。

    return path;
}

std::string readFile(const std::string &recource)
{
    std::ifstream in(recource, std::ifstream::binary);
    if(!in.is_open()) return "404";
    std::string content;
    std::string line;
    while(std::getline(in, line)) content += line;
    in.close();
    return content;
}
void handlerHttpRequest(int sock)
{
    char buffer[10240];
    ssize_t s = read(sock, buffer, sizeof buffer);
    if(s > 0) cout << buffer;
    std::string path = getPath(buffer);    从客户端请求的请求行中拿出请求的文件路径
    // path = "/a/b/index.html";
    // recource = "./wwwroot"; // 我们的web根目录
    // recource += path; // ./wwwroot/a/b/index.html
    // 1. 文件在哪里? 在请求的请求行中,第二个字段就是你要访问的文件
    // 2. 如何读取
    std::string recource = ROOT_PATH;    
    recource += path;                    给客户端请求的文件路径加上web根目录
    std::cout << recource << std::endl;

    std::string html = readFile(recource);  读取recource这个路径对应文件中的内容
    std::size_t pos = recource.rfind(".");
    std::string suffix = recource.substr(pos);
    cout << suffix << endl;

    //开始响应
    std::string response;
    response = "HTTP/1.0 200 OK\r\n";    下面的if:若是图片,添加图片对应的文件后缀
    if(suffix == ".jpg") response += "Content-Type: image/jpeg\r\n";
    else response += "Content-Type: text/html\r\n";
    response += ("Content-Length: " + std::to_string(html.size()) + "\r\n");
    response += "\r\n";
    response += html;

    send(sock, response.c_str(), response.size(), 0);
}

class ServerTcp
{
public:
    ServerTcp(uint16_t port, const std::string &ip = "")
        : port_(port),
          ip_(ip),
          listenSock_(-1)
    {
        quit_ = false;
    }
    ~ServerTcp()
    {
        if (listenSock_ >= 0)
            close(listenSock_);
    }

public:
    void init()
    {
        // 1. 创建socket
        listenSock_ = socket(PF_INET, SOCK_STREAM, 0);
        if (listenSock_ < 0)
        {
            exit(1);
        }
        // 2. bind绑定
        // 2.1 填充服务器信息
        struct sockaddr_in local; // 用户栈
        memset(&local, 0, sizeof local);
        local.sin_family = PF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));
        // 2.2 本地socket信息,写入sock_对应的内核区域
        if (bind(listenSock_, (const struct sockaddr *)&local, sizeof local) < 0)
        {
            exit(2);
        }

        // 3. 监听socket,为何要监听呢?tcp是面向连接的!
        if (listen(listenSock_, 5 /*后面再说*/) < 0)
        {
            exit(3);
        }
        // 运行别人来连接你了
    }
    void loop()
    {
        signal(SIGCHLD, SIG_IGN); // only Linux
        while (!quit_)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);

            int serviceSock = accept(listenSock_, (struct sockaddr *)&peer, &len);
            if (quit_)
                break;
            if (serviceSock < 0)
            {
                // 获取链接失败
                cerr << "accept error ...." << endl;
                continue;
            }
            // 5.1 v1 版本 -- 多进程版本 -- 父进程打开的文件会被子进程继承吗?会的
            pid_t id = fork();
            assert(id != -1);
            if(id == 0)
            {
                close(listenSock_); //建议
                if(fork() > 0) exit(0);
                //孙子进程
                handlerHttpRequest(serviceSock);
                exit(0); // 进入僵尸
            }
            close(serviceSock);
            wait(nullptr);
        }
    }

    bool quitServer()
    {
        quit_ = true;
        return true;
    }

private:
    // sock
    int listenSock_;
    // port
    uint16_t port_;
    // ip
    std::string ip_;
    // 安全退出
    bool quit_;
};

index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>104 期测试</title>
</head>

<body>
    <h3>hello my server!</h3>
    <p>我终于测试完了我的代码</p>
    <form action="/a/b/c.html" method="post">
        Username: <input type="text" name="user"><br>
        Password: <input type="password" name="passwd"><br>
        <input type="submit" value="Submit">
    </form>
    <!-- <img border="0" src="https://img1.baidu.com/it/u=1691233364,820181697&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500" alt="Pulpit rock" width="304" height="228"> -->
</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/159729.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6.2、客户/服务器方式(C/S)对等方式(P2P方式)

网络应用程序运行在处于网络边缘的不同的端系统上&#xff0c;通过彼此间的通信来共同完成某项任务。 开发一种新的网络应用首先要考虑的问题就是网络应用程序在各种端系统上的组织方式和它们之间的关系。\color{red}网络应用程序在各种端系统上的组织方式和它们之间的关系。网…

设计模式_创建型模式 -《建造者模式》

设计模式_创建型模式 -《建造者模式》 笔记整理自 黑马程序员Java设计模式详解&#xff0c; 23种Java设计模式&#xff08;图解框架源码分析实战&#xff09; 概述 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 分离了部件的构造&#…

Golang.org/x库初探2——text库

Golang有一个很有意思的官方库&#xff0c;叫golang.org/x&#xff0c;x可能是extends&#xff0c;experimental&#xff0c;总之是一些在官方库中没有&#xff0c;但是又很有用的库。最近花点时间把这里有用的介绍一下。 Golang.org/x库初探1——image库Golang.org/x库初探2—…

原创,探店,混剪,带货,获客,发布,更新,呆头鹅批量剪辑软件

一天轻松剪辑2000条&#xff0c;视频批量生成工具&#xff0c;短视频带货&#xff0c;电商卖家&#xff0c;媒体运营多场景应用视频剪辑分镜音频合成&#xff0c;一次解决&#xff01; 对于广大自媒体玩家最关心的话题&#xff0c;用了这个AI全自动呆头鹅批量视频剪辑软件做出来…

骑电动车不戴头盔识别抓拍系统 yolov7

骑电动车不戴头盔识别抓拍系统通过Python基于YOLOv7网络深度学习技术&#xff0c;对现场画面中骑电动车不戴头盔识别抓拍包括骑乘人员和带乘人员。YOLOv7 在 5 FPS 到 160 FPS 范围内&#xff0c;速度和精度都超过了所有已知的目标检测器&#xff0c;并在V100 上&#xff0c;30…

如何设置等高线坐标系并输出

如何设置等高线坐标系并输出发布时间&#xff1a;2018-01-17 版权&#xff1a;投影设置及数据导出矢量等高线生成完成后&#xff08;详细生成过程参加上一章节&#xff1a;矢量等高线生成&#xff09;,我们就能够设置投影和导出等高线数据。投影设置我们生成等高线默认的坐标是…

Rust之错误处理(一):无法恢复的错误panic!

开发环境 Windows 10Rust 1.66.1VS Code 1.74.3项目工程 这里继续沿用上次工程rust-demo 错误处理 错误是软件生活中的一个事实&#xff0c;所以Rust有一些处理出错情况的功能。在许多情况下&#xff0c;Rust要求你承认错误的可能性&#xff0c;并在你的代码编译前采取一些…

Google结构化数据

为什么要向网页添加结构化数据&#xff1f; 添加结构化数据可让您获得对用户更有吸引力的搜索结果&#xff0c;并可能会鼓励用户与您的网站进行更多互动&#xff0c;这就是富媒体搜索结果。 以下是一些为网站实现了结构化数据的案例研究&#xff1a; Rotten Tomatoes 为 10 万…

【学习笔记之Linux】工具之gdb

背景知识&#xff1a; 首先我们要知道&#xff0c;程序的发布一共有两种模式&#xff0c;一种是debug模式&#xff0c;是我们程序员自己编写代码的模式&#xff0c;可以进行调试&#xff0c;这个模式下编译出来的程序是包含调试信息的&#xff1b;一种是release模式&#xff0c…

AntV G6 组织图使用(后端渲染数据)

一、业务场景&#xff1a; 点击按钮&#xff0c;跳转页面并显示该数据的组织架构图&#xff08;类似于粒子效果&#xff09; 二、问题描述&#xff1a; 初始写死的数据能显示&#xff0c;但是从接口请求到的数据赋上值 渲染不了 三、具体实现步骤&#xff1a; &#xff08;1&…

python GUI And Tkinter 01

目录 一、基础介绍 二、创建窗口 1、创建完窗口后还需要知道窗口的相关属性 2、widget相关控件 3、原本tkinter有的Widget。 4、widget的共同属性 1. Configuration 2. Event Processing 3. Event callbacks 4. Alarm handlersafter(time,callback)&#xff1a;间隔指定时间后调…

Python logging 库的『完整教程』

前言 本文的标题是『完整』。所谓『完整』&#xff0c;大意是想表达&#xff1a;提炼出一组最小的经验组合&#xff0c;并且能够快速应用于工程中&#xff0c;能 work&#xff0c;甚至能完美地 work。这篇文章就是想要做到『如何能完美地work』。 初衷 最原始的初衷就是&…

nmap 扫描数据分析

本案22端口为开放端口&#xff0c;110为未开放端口 Wireshark上使用下面的表达式 ip.addr192.168.104.127 and ip.addr192.168.104.61 and tcp.port22 ip.addr192.168.104.127 and ip.addr192.168.104.61 and tcp.port110 命令一、 nmap -sS SYN-->SYN ACK-->RST …

电脑技巧:Windows这些自带应用尽量不要删,否则影响系统运行

目录 第一种&#xff1a;带有“microsoft”字样的软件尽量不卸载。 第二种&#xff1a;带有“Intel”或者“英特尔”的程序名称不要卸载。 第三种&#xff1a;windows驱动程序包尽量不要卸载 第四种&#xff1a;Adobe flash player不建议卸载 当电脑太卡&#xff0c;运行变…

C/C++ - 从代码到可执行程序的过程

&#xff08;1&#xff09;预编译 主要处理源代码文件中的以“#”开头的预编译指令。处理规则见下&#xff1a; 删除所有的#define&#xff0c;展开所有的宏定义。处理所有的条件预编译指令&#xff0c;如“#if”、“#endif”、“#ifdef”、“#elif”和“#else”。处理“#inc…

简单工厂模式

简单工厂模式所谓组件&#xff1a;从设计上讲&#xff0c;组件就是能完成一定功能的封装体。小到一个类&#xff0c;大到一个系统&#xff0c;都可以称为组件&#xff0c;因为一个小系统放到更大的系统里面去&#xff0c;也就当个组件而已。模式定义&#xff1a;提供一个创建对…

servlet运用自定义分发优化servlet泛滥

servlet优化 Web 层的 Servlet 个数太多了&#xff0c;不利于管理和编写 我们发现每一个功能都需要定义一个 servlet&#xff0c;一个模块需要实现增删改查功能&#xff0c;就需要4个 servlet&#xff0c;模块一多就会造成servlet 泛滥。此时我们就想 servlet 能不能像 servi…

YOLOv6 训练自己的数据集

项目地址&#xff1a;https://github.com/meituan/YOLOv6 论文地址&#xff1a;https://arxiv.org/abs/2209.02976 论文解析&#xff1a;http://t.csdn.cn/0ZQbV YOLOv6 是一种专为工业应用设计的单级对象检测框架&#xff0c;具有硬件友好的高效设计和高性能。YOLOv6-N 在 NVI…

【windows】docker与docker-compose部署spring boot项目

看完不会用&#xff0c;我倒立**&#xff0c;保姆级教学 docker部署项目 采用Dockerfile部署 docker-compose部署项目 docker-compose部署&#xff0c;实际上是对容器的编排&#xff0c;以及容器间的一些依赖 比如一个springboot项目&#xff0c;需要使用redis&#xff0c;…

深入 Redis sds

文末有视频讲解 在上一个模块中&#xff0c;我和小伙伴们一起学习了 Redis 最核心的命令&#xff0c;主要涉及 String、List、Hash、Set、Sorted Set 五种数据结构的命令&#xff0c;同时&#xff0c;我们还介绍了每种数据结构的实战场景&#xff0c;并带领小伙伴们使用 Java 语…