【Linux网络编程八】实现最简单Http服务器(基于Tcp套接字)

基于TCP套接字实现一个最简单的Http服务器

  • Ⅰ.Http请求和响应格式
    • 1.请求格式
    • 2.响应格式
    • 3.http中请求格式中细节字段
    • 4.http中响应格式中细节字段
  • Ⅱ.域名ip与URL
  • Ⅲ.web根目录
  • Ⅳ.Http服务器是如何工作的?
    • 一.获取请求
    • 二.分析请求
      • 2.1反序列化
      • 2.2解析url
    • 三.构建响应
      • 3.1构建响应正文
      • 3.2构建响应状态
        • ①404错误
        • ②302重定向
      • 3.3构建响应报头
        • ①Content-Length正文长度
        • ②Connection:keep-alive长短链接
        • ③Content Type报头属性
        • ④Set-Cookie会话保存
    • 四.返回响应
  • Ⅵ.实现最简单Http服务器

Ⅰ.Http请求和响应格式

1.请求格式

http请求由4部分构成:请求行,请求报头,空行,请求正文。每个部分都以‘\r\n’结束。

1.请求行:由Method URL HTTP version \r\n构成。也就是由请求方法,请求的资源,http的版本组成。
2.请求报头:里面存放的都是一些请求属性值,并且以Key:Values的形式存储。并且每种属性之间也是用’\r\n’分割。比如里面有一个Content-Length字段,表明的请求正文的长度是多少。
3.空行:单纯的空行,直接存储’\r\n’
4.请求正文:就是客户端要上传的内容,可以没有。
在这里插入图片描述

【注意】

这其实是我们在电脑上看到的格式,但在内存中,虽然每个部分都以’\r\n’结束,但’\r\n’也是字符。所以一个http请求就是一个字符串,只不过这个长字符串中间有很多个’\r\n’.
不过打印出来是多行的。

在这里插入图片描述

【空行的作用是什么?】

如何准确将报头和有效载荷分离?通过添加一个空行。空行之前就是整体报头,之后就是有效内容

【服务器如何读取一个完整的报文?】
1.在tcp缓冲区里,对整个宇符串(可能包含好几个请求)分析,那么你能确定服务器端读取报文时,就可以准确的能够读取到完整的一个报文吗?

不能!只能保证可以读取到完整的报头,因为如果读取到空行,那么空行之前的就是报头而之后的正文部分无法确定多长

2.那http是如何确保能够读取到一个完整的报文的?

①.首先完整的读取到一个报头
②.根据报头里的,报文属性Content-Length,得到正文部分的长度,然后从空行之后按照长度读取。

只有能保证服务器端读完整了,才可以进行网络序列化和反序列化。

示例:
在这里插入图片描述

2.响应格式

http响应也有4部分构成:状态行,响应报头,空行,响应正文,每个部分都以‘\r\n’结束。

1.状态行:由HTTP Version 状态码 状态码描述 ‘\r\n’组成,是描述本次请求的状态。
2.响应报文:与请求报头一样,里面是一些响应报文的一些属性,以Key: Value的形式存储。
3.空行:单纯’\r\n’。
4.响应正文:就是要请求的资源,比如图片,网站等。
在这里插入图片描述
【注意】
客户端在读取时,也无法确保能够准确的读取到完整的一个报文,所以需要添加一个空行。响应属性里也具有响应正文的长度。这样就可以读取到一个完整的报文了。

示例:
在这里插入图片描述
总结:
在这里插入图片描述

3.http中请求格式中细节字段

  • 1.1 HTTP请求中的请求方法

在这里插入图片描述

浏览器提交数据给服务器都是通过表单提交的!
在这里插入图片描述

  • 1.2 GET与POST的区别
    如果你今天想去啊?获取网页你就只用get方法就可以好不管是图片视频音频啊,我们就用get方法呃,但是如果你想把你的参数提交给服务端那么此时你可以选择post方法也可以可以选择get.
    实际上,我们通常是通过一个叫做表单的东西来提交参数的,然后我们去提参的时候,如果我们对应的表单提参方法采用的是get方法,那么其中它对应的参数呢,就会拼接到我们url的后面。然后用?作为分隔符,然后呢左侧是你要访问的资源右侧是呃右侧是你要提交的参数。参数参数之间用&分割。

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

POST方法在提交参数时,不是通过url来提交的,而是通过正文部分将参数提交给服务器的。
在这里插入图片描述
所以POST方法也支持参数提交,采用请求的正文提交参数!
【总结】
在这里插入图片描述

4.http中响应格式中细节字段

Http响应的状态码:

在这里插入图片描述
最常见的状态码,比如200(OK),404(Not Found),403(Forbidden),302(Redirect,重定向),504(Bad Gateway)。
404错误本质就是因为客户端发起的请求不合理。

HTTP常见Header:

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

Ⅱ.域名ip与URL

Ⅲ.web根目录

第一组知识:

就是我们将来收到一个请求的时候,我们给别人进行响应,响应的时候,我们自己要添加我们自己默认的一些报头还有它的一些状态码了协议版本了,空行了这些字段.我们的网页,图片,也就是资源呢,其实是会被拼接到响应的正文部分!

第二组知识:

那么别人请求的时候呢?他通常会通过在请求里面包含他要请求什么网页,他会包含我要请求什么样的资源,把路径呢通过url给我们呈现出来,那么所以呢,我们的服务器就可以获取到路径,就可以动态的根据路径去挑选,他想要的资源,而我们的资源其实都是存放在一个个的文件里。

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

【web根目录本质】

我在我的服务器进程路径下存在一个wwwroot的文件夹好,这是什么意思呢?将来我想把我的所写的所有的网页所有的图片所有的视频包括我的网站的首页全放在这个目录里面好.以目录以树状结构的形式,从这个目录开始让别人去访问我们把这个目录下的文件,这叫做web根目录.本质就是存放资源的一个统一路径。

http协议呢,它其实,一定要有自己的web根目录,这个web根目录可以是linux的根目录也可以由你自己去指定。

【浏览器(Client)指定路径下将请求的文件内容】
在这里插入图片描述
【存在问题】
客户端不管请求什么目录文件,都访问的是wwwroot目录下html文件的内容所以我们想让客户端请求什么目录文件,服务器就返回该目录下的文件内容,该如何做呢?

必须解析请求行中的url

Ⅳ.Http服务器是如何工作的?

重点:我们要理解一个http服务器,它是怎么工作的,http服务器它无非就是在对http请求的内容在进行,我们对应的解析。

我们的重点是什么呢?重点是你要去理解http的请求,它无非就是通过套接字,我们(http服务器)读到了它的http的请求,读到了它的请求然后按照我们http的上面的这个格式(反序列化),把它给它解析出来提取url然后呢,我们给它构建响应把响应再给它返回去此时,这个就叫做http协议。

我们的浏览器访问服务器的本质实际上是把我们的服务器上的指定路径下的网页资源获取到浏览器当中然后由浏览器进行解释。最后就看到了网页效果。

【总结】
其实所有的协议本质都是对‘字符串′做分析处理

一.获取请求

从网络里获取到的请求是字符串形式的,但字符串形式服务器并不认识,需要反序列化成结构体(客户端和服务器端都认识的结构体)
在这里插入图片描述

二.分析请求

2.1反序列化

将读取到的字符串分割构成服务器认识的请求格式,也就是最上面讲到到http请求格式,由请求行,请求报头,空行,请求报文组成,我们需要构建一个request类。

这个工作。其实就是把他的请求做字符串做分析,按行做分析(反序列化)。把一整个字符串分割成若干个字符串。
分析完之后之后呢?然后我们再把正文部分直接也拿出来,把它的每一行也都分别push到vector里就可以了(构建初始化req对象)最后直接将正文部分放进text中。

class HttpRequest
{
public:void Deserialize(std::string req)//反序列化将字符串分割构建结构体对象{while(true){std::size_t pos=req.find(seq);if(pos==std::string::npos)break;std::string temp =req.substr(0,pos);if(temp.empty())break;req_header.push_back(temp);req.erase(0,pos+seq.size());}text=req;
public:std::vector<std::string> req_header;std::string text;//服务器分析的结果std::string method;//请求方法std::string url;//请求资源std::string http_version;//http版本std::string resource_path;//资源路径std::string suffix;//文件后缀
};

【注意】

存在问题:默认从套接字里读取到的就是一个完整的报文没有做处理

2.2解析url

解析url的目的就是为了让服务器返回客户端所指定的资源(客户端通过url形式指定资源路径)
就是将url中的资源路径resource_path给获取到。

而进一步解析:解析请求行(在vector容器中的第一个元素)

void Split(){std::stringstream ss(req_header[0]);ss>>method>>url>>http_version;resource_path=wwwtew;if(url=="/"||url=="/index.html"){resource_path+="/";resource_path+=homepage;}else{resource_path+=url;}
}

如果服务器收到的这个http请求他的url只是一个斜杠,这其实表明的就是他要请求我们的web根目录那么此时,我们只会把整个网站的叫做首页给你返回那么,这个首页呢,我们就叫做index.html

在这里插入图片描述

【跳转网页】
在这里插入图片描述

三.构建响应

服务器获取到请求后,分析请求,将请求的资源,以HTTP响应的方式返回给客户端。

3.1构建响应正文

先将浏览器请求的资源构建出来,因为服务器已经解析出url中资源路径,所以服务器直接可以通过资源路径定位到对应的文件中,并从文件中读取出来,存放在正文中。

服务器动态读取资源文件,构建响应正文

 static std::string ReadHtmlContent(const std::string &htmlpath){//这里存在一个坑--二进制读取存在问题//std::ifstream in(htmlpath);std::ifstream in(htmlpath,std::ios::binary);if(!in.is_open()) return " ";//如果打开文件失败说明客户端的请求不合理返回空//获取文件的大小in.seekg(0, std::ios_base::end);auto len = in.tellg();in.seekg(0, std::ios_base::beg);//提前开辟空间存放二进制std::string content;content.resize(len); in.read((char*)content.c_str(), content.size());/*std::string content;std::string line;while(std::getline(in,line)){content+=line;}*/in.close();return content;}

3.2构建响应状态

①404错误

当服务器读取资源文件时,可能会读取失败,因为客户端不合理的请求,请求不存在的资源。这时服务器就会访问到空资源。

当服务器访问到空资源时,我们就让浏览器再重新请求404网页资源,也就是服务器将404网页资源返回给浏览器。
在这里插入图片描述

   std::string text;bool ok =true;text=ReadHtmlContent(req.resource_path);//可能会读取失败,因为客户端不合理的请求,请求不存在的资源if(text.empty())//访问不存在的资源,就让浏览器申请404网页资源{ok=false;std::string err_html=wwwtew;err_html+="/";err_html+="err.html";//404网页资源text=ReadHtmlContent(err_html);}std::string response_line;//并将状态码设置成404if(ok)response_line="HTTP/1.0 200 OK\r\n";elseresponse_line="HTTP/1.0 404 Not Found\r\n";

err.html:


<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404 Not Found</title>
<style>
body {
text-align: center;
padding: 150px;
}
h1 {
font-size: 50px;
}
body {
font-size: 20px;
}
a {
color: #008080;
text-decoration: none;
}
a:hover {
color: #005F5F;
text-decoration: underline;
}
</style>
</head>
<body>
<div>
<h1>404</h1>
<p>页面未找到<br></p>
<p>
您请求的页面可能已经被删除、更名或者您输入的网址有误。<br>
请尝试使用以下链接或者自行搜索:<br><br>
<a href="https://www.baidu.com">百度一下></a>
</p>
</div>
</body>
</html>
②302重定向

3XX重定向原理(依赖Location字段)
1.重定向的意思:让服务器指导我们的浏览器访问新的地址,这个新的地址就存在location属性字段中。
2.3XX对应的意思
第一我要访问的资源,服务器无法给我提供对应服务。
第二,我们对应的这个要去的新地址呢,有location指定。
所以你的这个浏览器它会二次发起请求,二次发起请求的时候,那么,这个时候,它请求的就不再是这个了服务器了,而是根据它给location的地址重新构建http请求,去访问新的地址,

在这里插入图片描述

其实就是http response通过3XX这样的状态码,然后配合location让浏览器发起二次请求就可以了

3.3构建响应报头

①Content-Length正文长度
        std::string response_header="Content-length: ";//构建响应报头 response_header+=std::to_string(text.size());response_header+="\r\n";
②Connection:keep-alive长短链接
  • 短链接

一个巨大的页面是会包含非常多的元素的!每一个元素就是一个资源!

一个完整的网页了,每一张图片就是一个文件资源,所以要让浏览器得到这个图片就要发起一次http请求,所以一个网页上面有100张图片,浏览器会先.
获取这个网页,获取这个网页的同时呢?我们这个网页内部可能还需要包含很多很多的图片,那么,浏览器可能需要再二次三次十次八次继续发起请求好,也就是说对我们今天我们的服务器来讲呢,要获取一个100张图片网页我们要发起101次http的请求。就可能一瞬间就要创建几十,甚至上百个线程来把每一个资源都推送给我们的浏览器然后让让它呢帮我们把我们对应的资源呢返回返回到我们的浏览器让它去渲染。

这种基于请求一次,响应一次然后关闭链接这种我们称之为叫做短链接响应(http/1.0)一次请求只拿回来一个资源,然后关闭链接
在这里插入图片描述

  • 长连接

建立一个TCP连接,发送和返回多个http的request和response。这个链接在本轮请求没有完全结束之前链接不关闭,本轮请求比如,你把一个网页该要的100个资源全拿到了本轮请求全部完毕,那么此时,该链接再断开这种我们称之为叫做长链接(http/1.1),一次请求拿回来多个资源。

Connection: keep-alive
所以呢,当我们通信双方在进行最开始几次那么进行http请求时,服务器和客户端双方是需要,协商http版本的,协商http版本来证明,我们双方是否支持叫做长链接技术然后呢?但是在协商,我们都支持支持之后,我可以不用呀。那么所以怎么样能证明,我们2个都要选择使用长链接呢?
那么此时就有connection选项叫做keep alive选项它表明的是我们是否在双方通信时,选择使用长链接,当客户端和服务器connection选项都是keep alive时双方即会采用长链接的方案来进行通信

③Content Type报头属性

根据短链接,我们知道,如果一个网页中包含图片时,浏览器在访问这个网页时,首先会发起链接访问网页资源,然后识别到还有图片,则会自动发起二次链接获取图片资源。然后将图片资源也显示出来。
在这里插入图片描述
但浏览器请求的资源非常多啊,并且我的服务器上呢,这个图片呢,有png的也有jpg的,那么就是服务器怎么知道浏览器要请求的是什么类型的文件呢?因为只有它的请求的文件的类型确定了,服务器才好填我们的Content type,这样将响应返回时,浏览器才能按照对应的格式显示出来。
该怎么做呢?图片的类型完全根据文件的后缀!
所以服务器只要找到对应的图片的文件路径,并将文件的后缀提取出来,就可以找到浏览器想要什么类型的图片了,就可以将图片类型填写到Content-Type属性中。

两件工作
第一件工作,需要我(服务器)能够在读取你的请求时,就已经知道你的http请求的资源的后缀是什么。通过url路径中资源路径就可以找到。
在这里插入图片描述

第二个工作,要维护了一个简单的映射表。存储的是文件后缀对应的Content-Type类型。(利用unordermap做一个content的映射表)

在这里插入图片描述

        response_header+="Content-Type: ";response_header+=SuffixToDesc(req.suffix);response_header+="\r\n";

[问题]
在这里插入图片描述

④Set-Cookie会话保存

http协议呢?本身它是没有状态的,请求什么资源就是什么资源。

应用场景:访问B站
浏览器你发的任意一个链接请求都有要你登录验证,为什么?
因为间每一个资源都要到对你进行身份认证,因为我们必须得是登录验证状态才能问某些资源,那么我们登入B站后,再访问n多个视频(n个资源)时为什么都不需要你再登入验证呢?

也就B站服务器怎么知道我一直是处于登录状态的呢。这就是我们的会话保持的功能的一个概念。

Set-Cookie原理
第一次登入B站时,访问B站登入页面服务器,服务器如果发现你的请求报文里面没有携带cookie信息,此时,服务器就直接跳转到登录页面让你去登录验证.但是呢,只要你曾经注注册并登录过,然后你的浏览器请求一次之后呢认证通过之后,就会把密码和账号信息就写到了这个浏览器的cookie文件往后每次请求都会携带cookie,所以我们此时b站就会自动进行认证了
一自动携带,二自动认证所以从此往后你就不需要再去输入什么账号和密码。

验证:

        response_header+="Set-Cookie: name=tao&&passwd=123456789";response_header+="\r\n";

第一次访问服务器将对应的cookie返回,则浏览器会将cookie信息保存到cookie文件中,等下次请求时,就默认会将cookie信息带上。
在这里插入图片描述

【cookie的保存方法】
我们对应的浏览器要保存这个cookie文件,它通常有两种保存方法第一种是文件级,第2种是内存级。

意思就是说浏览器,它收到了这个cookie,因为浏览器本身是一个进程,那这个进程内部是可以new malloc空间的,所以呢它收到它登入成功之后,它就可以把cookie信息就残留在浏览器进程的这个内存当中,它不往磁盘上写。
所以这个时候呢,你不关浏览器,你可以一直访问你一旦把浏览器关掉了。那么,你再把浏览器重新打开再访问b站你又要重新登录了好这是内存级.

如果你的浏览器它设置的cookie文件的保存呢,是直接把它保存到文件当中,这个文件呢,本身就是浏览器在浏览器的特定的安装路径下就会存在这样的文件文件级的cookie那么文件级的cookie呢,大家都知道文件呢,是在磁盘当中的所以你把浏览器即便关掉了好即便你关掉了,你照样可以不用登录了好这就是文件级。

四.返回响应

       std::string blank_line="\r\n";//构建空白行std::string response=response_line;//添加状态行response+=response_header;//添加响应报头response+=blank_line;//添加空行response+=text;//添加响应正文write(sockfd,response.c_str(),response.size());//发送给客户端

Ⅵ.实现最简单Http服务器

HttpServer.hpp

#include <iostream>
#include <pthread.h>
#include "Socket.hpp"
#include "Log.hpp"
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
#include <unordered_map>
Log log;
const uint16_t defaultport=8888;
const std::string wwwtew="./wwwtew";
const std::string homepage="index.html";
const std::string seq="\r\n";
class HttpServer;
class pthreadData
{
public:pthreadData(int sockfd,HttpServer*s):_sockfd(sockfd),svr(s){}
public:int _sockfd;HttpServer* svr;
};
class HttpRequest
{
public:void Deserialize(std::string req)//反序列化将字符串分割构建结构体对象{while(true){std::size_t pos=req.find(seq);if(pos==std::string::npos)break;std::string temp =req.substr(0,pos);if(temp.empty())break;req_header.push_back(temp);req.erase(0,pos+seq.size());}text=req;}void Split(){std::stringstream ss(req_header[0]);ss>>method>>url>>http_version;resource_path=wwwtew;if(url=="/"||url=="/index.html"){resource_path+="/";resource_path+=homepage;}else{resource_path+=url;}//分割出资源路径后,就可以获取对应的文件后缀auto pos=resource_path.rfind(".");if(pos==std::string::npos)suffix=".html";//默认是html类型else suffix=resource_path.substr(pos);}void DebugPrint(){for(auto &line : req_header){std::cout << "--------------------------------" << std::endl;std::cout << line << "\n\n";}std::cout << "method: " << method << std::endl;std::cout << "url: " << url << std::endl;std::cout << "http_version: " << http_version << std::endl;std::cout << "resource_path: " << resource_path << std::endl;std::cout << text << std::endl;} 
public:std::vector<std::string> req_header;std::string text;//服务器分析的结果std::string method;std::string url;std::string http_version;std::string resource_path;std::string suffix;//文件后缀
};
class HttpServer
{
public:HttpServer(uint16_t port=defaultport):_port(port){}bool Start(){_listensock.Socket();_listensock.Bind(_port);_listensock.Listen();for(;;){std::string clientip;uint16_t clientport;int sockfd=_listensock.Accept(&clientip,&clientport);log(Info,"connect success sockfd:%d",sockfd);pthreadData* td=new pthreadData(sockfd,this);pthread_t tid;pthread_create(&tid,nullptr,ThreadFunc,td);}  }static std::string ReadHtmlContent(const std::string &htmlpath){//这里存在一个坑--二进制读取存在问题//std::ifstream in(htmlpath);std::ifstream in(htmlpath,std::ios::binary);if(!in.is_open()) return " ";//如果打开文件失败说明客户端的请求不合理返回空//获取文件的大小in.seekg(0, std::ios_base::end);auto len = in.tellg();in.seekg(0, std::ios_base::beg);//提前开辟空间存放二进制std::string content;content.resize(len); in.read((char*)content.c_str(), content.size());/*std::string content;std::string line;while(std::getline(in,line)){content+=line;}*/in.close();return content;}//获取文件后缀对应的类型 std::string SuffixToDesc(const std::string &suffix){auto iter=suffix_type.find(suffix);if(iter==suffix_type.end())return suffix_type[".html"];else return suffix_type[suffix];}void HanderHttp(int sockfd){char buffer[10240];//1.服务器获取客户端发起的请求(字符串形式服务器并不认识,需要反序列化成结构体)ssize_t n=read(sockfd,buffer,sizeof(buffer)-1);if(n>0){buffer[n]=0;std::cout<<buffer;HttpRequest req;req.Deserialize(buffer);req.Split();//req.DebugPrint();//1.1服务器对请求进行解析,分析url//2.服务器返回响应给客户端//2.1构建响应//std::string text=ReadHtmlContent(req.resource_path);//构建正文 动态的从文件里读取对应的资源内容,并且根据客户端url来搜索资源//std::string response_line="HTTP/1.0 200 OK\r\n";//构建响应状态行std::string text;bool ok =true;text=ReadHtmlContent(req.resource_path);//可能会读取失败,因为客户端不合理的请求,请求不存在的资源if(text.empty())//访问不存在的资源,就让浏览器申请404网页资源{ok=false;std::string err_html=wwwtew;err_html+="/";err_html+="err.html";text=ReadHtmlContent(err_html);}std::string response_line;//并将状态码设置成404if(ok)response_line="HTTP/1.0 200 OK\r\n";elseresponse_line="HTTP/1.0 404 Not Found\r\n";//response_line="HTTP/1.0 302 Found\r\n";//302配合location实现重定向std::string response_header="Content-length: ";//构建响应报头 response_header+=std::to_string(text.size());response_header+="\r\n";response_header+="Location: https://www.baidu.com\r\n";response_header+="Content-Type: ";response_header+=SuffixToDesc(req.suffix);response_header+="\r\n";response_header+="Set-Cookie: name=tao&&passwd=123456789";response_header+="\r\n";std::string blank_line="\r\n";//构建空白行std::string response=response_line;response+=response_header;response+=blank_line;response+=text;write(sockfd,response.c_str(),response.size());}close(sockfd);}static void *ThreadFunc(void *avgs){pthreadData*td=static_cast<pthreadData*>(avgs);pthread_detach(pthread_self());td->svr->HanderHttp(td->_sockfd);  delete td;return nullptr;}~HttpServer(){}
private:Sock _listensock;//本质是sockfduint16_t _port;std::unordered_map<std::string,std::string> suffix_type;
};

HttpServer.cc

#include <iostream>
#include "HttpServer.hpp"
#include <memory>
using namespace std;int main()
{HttpServer*svr=new HttpServer();svr->Start();}

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

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

相关文章

RK3588开发板利用udp发送和接收数据

目录 1 send.cpp 2 receive.cpp 3 编译运行 4 测试 1 send.cpp #include <iostream> #include <string> #include <cstring> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> //…

海外合规|新加坡网络安全认证计划简介(三)-Cyber Trust

一、 认证简介&#xff1a; Cyber Trust标志是针对数字化业务运营更为广泛的组织的网络安全认证。该标志针对的是规模较大或数字化程度较高的组织&#xff0c;因为这些组织可能具有更高的风险水平&#xff0c;需要他们投资专业知识和资源来管理和保护其 IT 基础设施和系统。Cy…

开源 AI 智能名片 O2O 商城小程序:引入淘汰机制,激发社交电商新活力

摘要&#xff1a;本文深入探讨在社交电商领域中&#xff0c;开源 AI 智能名片 O2O 商城小程序如何通过设置淘汰机制&#xff0c;实现“良币驱逐劣币”&#xff0c;激励士气&#xff0c;为社交电商企业注入新的活力。通过分析缺乏淘汰机制的弊端以及设置淘汰机制的优势&#xff…

CAAC无人机飞行执照理论培训课程详解

CAAC&#xff08;中国民用航空局&#xff09;无人机飞行执照的理论培训课程是确保无人机飞手全面掌握飞行和应用技能的重要环节。以下是对该理论培训课程的详细解析&#xff1a; 一、课程目标 理论培训课程的主要目标是使学员&#xff1a; 了解并掌握无人机相关的法律法规、…

Java基于微信小程序的家庭财务管理系统,附源码

博主介绍&#xff1a;✌Java徐师兄、7年大厂程序员经历。全网粉丝13w、csdn博客专家、掘金/华为云等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不…

EmguCV学习笔记 VB.Net 8.4 pyrMeanShiftFiltering

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

Java项目:137 springboot基于springboot的智能家居系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本基于Springboot的智能家居系统提供管理员、用户两种角色的服务。 总的功能个人中心、基础数据管理、家具管理、任务管理和用户管理。本系统…

显微镜基础知识--脑机起步

一、显微镜类别 学生级、实验级、研究级生物显微镜单目型、双目型、三目型生物显微镜 二、显微镜基础原理 &#xff08;1&#xff09;光学显微镜 光学显微镜主要由目镜、物镜、载物台和反光镜(集光镜)组成。目镜和物镜都是凸透镜&#xff0c;焦距不同。物镜的凸透镜焦距小于…

Web攻防之应急响应(二)

目录 前提 &#x1f354;学习Java内存马前置知识 内存马 内存马的介绍 内存马的类型众多 内存马的存在形式 Java web的基础知识&#xff1a; Java内存马的排查思路&#xff1a; &#x1f354;开始查杀之前的需要准备 1.登录主机启动服务器 2.生成jsp马并连接成功 …

MATLAB 仿真跳频扩频通信系统

1. 简介 跳频扩频&#xff08;FHSS&#xff09;是一种通过在不同的频率之间快速切换来对抗窄带干扰的技术。在这篇博客中&#xff0c;我们将使用 MATLAB 进行 FHSS 通信系统的仿真&#xff0c;模拟跳频过程、调制、解调以及信号在不同步骤中的变化。通过对仿真结果进行可视化&…

python-简单的dos攻击

前言 这个是DOS攻击学习(注意&#xff1a;千万别去攻击有商业价值的服务器或应用&#xff0c;不然会死的很惨(只有一个IP通过公网访问容易被抓),前提是网站没有攻击防御) 创建一个以python编写的后端web服务(好观察) 安装flask pip install flask from flask import Flaskapp …

前端入门了解

1. 网页 1.1 网页概述 1.2 超文本标记语言 1.3 网页的形成 2. 浏览器了解 网页需要通过浏览器来展示&#xff0c;下面是关于浏览器的两点; 国际上通用的浏览器有如下六个&#xff08;百度&#xff0c;360&#xff0c;uc等是主要在国内使用&#xff09;&#xff0c; 3. We…

Apple 重發iOS 17.6.1 修正版

蘋果又再次替 iPhone 和 iPad 用戶釋出 iOS 17.6.1更新&#xff08;21G101&#xff09;&#xff0c;這次更新與8日所推出的 iOS 17.6.1 正式版相同&#xff0c;官方在更新說明內也沒有提到任何修改&#xff0c;依舊是維持修正進階資料保護的問題 iOS 17.6.1 更新修正版內容重點…

面向切面编程

1. 增删改查 三层干啥 2. 文件上传 第三方api(接口) 调用准备 -- 官方代码 -- 工具类 3. 登录鉴权 登录(查询 密码) 鉴权(拦截器)登录完成后--后台生成token返回给浏览器--每次浏览器发请求时候携带token--服务器需要使用拦截器拦截请求,获取token--校验token生成 token校…

借老系统重构机会我写了个groovy规则引擎

公司老系统的重构计划早就有了&#xff0c;为了对Java硬编码的各种校验规则进行重构&#xff0c;特地参考了相关技术&#xff0c;最终选择了groovy进行了系统的学习&#xff0c;并编写了一个即插即用的轻量级规则引擎。 文章目录 项目背景技术选型groovy的性能groovy脚本执行线…

【拉取Git项目到本地,知识小记,后续再改】

前提&#xff1a;Git已经安装好 https://blog.csdn.net/mukes/article/details/115693833 安装至步骤2.2.4即可 第一步创建本地项目目录 第二步获取他人提供的项目git地址或者自己在网上找的他人项目的git地址 Git 全局设置: git init git config --global user.name “ASxx”…

1998-2023年上市公司金融/信贷/资本资源错配程度数据(含原始数据+计算代码+结果)

1998-2023年上市公司金融/信贷/资本资源错配程度数据&#xff08;含原始数据计算代码结果&#xff09; 1、时间&#xff1a;1998-2023年 2、来源&#xff1a;上市公司年报 3、指标&#xff1a;证券代码、year、应付账款、负债合计、利息支出、行业代码、是否ST或PT、上市日期…

Webpack详解与配置环境

webpack&#xff1a;webpack网址 1、工作原理&#xff1a; Webpack是一个非常强大的静态模块的打包工具。从文件入口开始&#xff0c;递归解析以来关系&#xff0c;然后将所有模块打包成一个或多个budle文件。 2、webpack核心概念&#xff1a; Entry&#xff1a;入口起点(en…

Linux——redis理论、安全模型

一、redis 主要的data type redis 的原生客户端redis 支持通过python php golang 等语言连接redis 主要适用场景 二、redis如何进行数据存储 非关系数据库 不使用二维表 redis 使用键值对完成数据的存储redis一共有16个库 &#xff0c;不同的库使用编号 0-15redis 在…

设计模式-装饰器代理观察者

3.7 装饰器模式&#xff08;代码见vs&#xff09; 装饰器又叫做包装模式&#xff0c;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构。这种模式创建了一个装饰类&#xff0c;用来包装原有的类&#xff0c;并在保持类方法完整性的前提下&#xff0c;提供了额…