【Linux网络编程】应用层协议HTTP(实现一个简单的http服务)
目录
前言
一,HTTP协议
1,认识URL
2,urlencode和urldecode
3,HTTP协议请求与响应格式
二,myhttp服务器端代码的编写
HTTP请求报文示例
HTTP应答报文示例
代码编写
网络通信模块
处理请求和发送应答模块
结果展示
完整代码
main.cc 文件
http.hpp文件
makefile
相关测试网页(html形式)
前言
虽然说,应用层协议是需要我们程序猿自己定的。但是实际上,已经有大佬们定义了一些现成的,非常好用的应用层协议,供我们直接使用 。HTTP(超文本传输协议 )就是其中之一。
在互联网世界中,HTTP(HyperText Transfer Protocol,超文本传输协议)是一个至关重要的协议。它定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或传输超文本(如HTML)。
一,HTTP协议
HTTP协议是客户端与服务器之间通信的基础。客户端通过HTTP协议向服务器发送请求,服务器收到请求后处理并返回响应。
1,认识URL
URL是Uniform Resource Location的缩写,译为“统一资源定位符”。
我们平时所说的网址,就是URL,例如:
- 开始部分https:表示我们获取资源采用的协议,这里的https起始是对http协议的一种加密,这里我们看作是http。
- news.qq.com:这一部分表示域名,通过域名 可以找到要访问服务器的IP地址。如何找到呢?
- 域名服务器是网络中的基础设施建设,内部保存着域名和对应的IP地址,当时使用浏览器访问百度时,浏览器内部一般内置了域名服务器的IP地址,比如8.8.8.8。通过域名服务器获取到IP地址,这个过程叫做DNS。最后进行对目标服务器的访问。
- 但是,要访问目标服务器,需要知道IP地址+端口号,IP地址可以通过域名 获取到,但是端口号呢?其实,对于这些成熟的协议,端口号是固定的。https对应的端口号是443,http对应的端口号是80,ssh对应的端口号是22。
- 而域名之后的剩余部分,/ch/tech:是我们要访问的资源路径。可以发现,其中"/",就是linux下的路径分割符,所以该部分就代表linux系统下的一个特定路径。
- 而我们上网的行为分为两种,一个是从远端拿下来数据,另一个是将数据上传到远端,这其实就是IO。而我们想从远端拿下来数据时,就是获取资源,这些资源在哪呢?就在linux服务器内部,特定路径下的一个文件。
- 通过这条URL,域名可以找到IP(具有唯一性),而路径,目标机器上特定 路径下的一个文件(也具有唯一性),所以通过URL可以定位到全网内特定的一个文件。
2,urlencode和urldecode
像?/:这样的字符,已经被当作特殊字符理解了。因此这些字符不能随意出现。如果出现了这些特殊意义的字符,需要客户端(一般是浏览器)对这些特殊字符进行编码(encode)。服务器自己需要进行解码decode。示例:
hello @??// word编码后的结果是:
解码后的结果是:
工具: UrlEncode编码/UrlDecode解码 - 站长工具
3,HTTP协议请求与响应格式
HTTP底层使用的是tcp协议。
HTTP请求(request)
首行:【方法】+【url】+【版本号】
Header:请求的属性,以冒号分割的键值对。每组属性之间使用\r\n分割,遇到空行表示Header结束。
DATA:空行后面的内容都是DATA。DATA允许为空。
HTTP响应格式(response),与请求格式类似。
二,myhttp服务器端代码的编写
HTTP请求报文示例
- 这里的uri是统一资源定位符,它的作用是,可以唯一的标识资源,并允许用户通过特定的协议与资源进行交互。而前面提到的url,是统一资源标识符,url是uri的一种形式。
- 在上面的内容中提到过,url统一资源标识符,也就是网址。它的域名之后的内容,其实是特定linux机器上的特定路径的一个文件,我们使用 url(网址)的时候,其实就是访问目标主机上特定路径下的一个文件。
- 在这里,请求行中的uri,也代表要访问的路径 。
- 需要注意的是,在uri中 ,"/"不是指linux下的根目录,而是web根目录。什么是web根目录?就是和当前项目在同一级的一个目录,其内部可能包含网址,图片,视频等等各种资源,所以我们实际访问的其实是是web根目录下的资源。
将整个请求看作是一个大的字符串,中间使用\r\n,或者使用一些空格,空行分割。
编写代码时的想法:
- 为了表示这个大字符串,我们可以定义一个Request请求类来管理。
- 类中的成员就包含请求行的三个属性,用三个字符串表示即可。中间部分是以键值对的形式,所以可以使用unordered_map来存储,还有一个空行,和正文部分,使用string即可。
- 当我们的服务器端收到这个请求报文时,就需要对这个大字符串进行反序列化,填充类中的成员。也就是将这个大的字符串,转化为结构化数据。
HTTP应答报文示例
和请求报文结构类似。
- 同样我们定义一个response应答类,和request类似。从上图可以看出,其实正文部分,就是一个html,是我们要返回给客户端的一个网页。也就是客户端想要访问的资源。
- 将来我们的response类中一定会包含一个string _text。表示正文部分。我们拖过客户端发来的请求报文,可以知道客户端想要访问是么资源,可以查看uri。如果我们将资源硬编码到代码中,那么就只可以访问一个文件。比如将html文件,当成一个大字符串,_text存储这个大字符串。那么我们在发送应答的时候,返回的就永远是这一个资源,所以不能将资源硬编码到代码中。
- 我们可以根据客户端发来的请求,提取uri,找到要访问的资源。然后以打开该文件,再读取文件中的内容即可。
- 最后发送 给客户端,需要我们将类中的成员序列化成一个大的字符串。也就是将结构化数据,转化为大的字符串。
代码编写
- 现在我们大概了解了HTTP协议的请求格式和应答格式。接下来使用浏览器作为客户端,发送请求,接受应答。我们自己编写一个myhttp服务器,对客户端发来的HTTP请求做解析,然后返回给客户端应答。
- HTTP协议是基于tcp的。
- 在这里使用多进程的方式,父进程不停的获取连接,子进程不断处理连接。
首先是网络通信部分代码:
核心逻辑:
- 服务端
- 创建套接字 → 绑定地址 → 监听连接 → 接受请求 → 读取数据 → 回传数据。
网络通信模块
const int gbacklog = 8;
int main(int argc, char *argv[])
{// 1,创建套接字int listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd < 0){std::cerr << "创建监听套接字失败" << std::endl;exit(1);}// 从命令行参数中获取端口号uint16_t port = std::stoi(argv[1]);// 填写sockaddr_in结构体,注意主机序列转化为网络字节序struct sockaddr_in addr;int addrlen = sizeof(addr);addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = INADDR_ANY;// 2,绑定端口号和ip地址int n = bind(listenfd, (struct sockaddr *)&addr, sizeof(addr));if (n < 0){std::cerr << "绑定失败" << std::endl;exit(2);}// 3,开始监听int s = listen(listenfd, gbacklog);if (s < 0){std::cerr << "监听失败" << std::endl;exit(3);}// 4,获取连接,处理连接while (true){int sockfd = accept(listenfd, (struct sockaddr *)&addr, (socklen_t *)&addrlen);if (n < 0){std::cerr << "获取连接失败" << std::endl;continue; // 继续获取}// 创建子进程处理请求pid_t id = fork();if (id == 0){// 子进程// 关闭不需要的文件描述符close(listenfd);if (fork() > 0)exit(0); // 子进程退出// 孙子进程 处理请求handle_request(sockfd);// 孙子进程退出exit(0);}else if (id > 0){// 父进程// 关闭不需要的文件描述符close(sockfd);pid_t rid=::waitpid(id,nullptr,0);(void)rid;}else{std::cerr << "创建子进程失败" << std::endl;}}return 0;
}
至此实现了网络通信的功能。 通过回调函数处理客户端(浏览器)发送过来的请求。
处理请求和发送应答模块
- 接下来就是子进程处理请求。
- 现在实现requet类和response类,其中request需要实现反序列化,将大字符串变成一个结构化数据。而response需要实现序列化,将序列化数据转化为结构化数据。
- 需要注意的是,我们在给客户端发送应答报文的时候,必须要发送状态行(也就是报文的第一行),它包含了HTTP版本,状态码和状态码描述,这些是必须返回给客户端的,而其他的内容 可以不发。
通过回调方法处理请求,发送应答
// 定义一个回调方法,处理请求
void handle_request(int sockfd)
{char buffer[BUFFER_SIZE];// 读取请求报文ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1,0);if (n > 0){buffer[n] = 0;//for debug//std::cout<<buffer<<std::endl;Request req;// 将读取到的字符串反序列为请求对象req.Deserilaze(buffer);// 构建应答报文Response resp;//获取客户端想要访问的资源文件resp.SetTargetFile(req.GetUri());//for debug//std::cout<<"##############################"<<std::endl;//std::cout<<req.GetUri()<<std::endl;//std::cout<<"##############################"<<std::endl;// 将目标文件内容填写到正问部分resp.SetText();resp._version = "HTTP/1.1";resp._code = 200; // successresp._desc = "OK";// 反序列化std::string resp_str = resp.Serilaze();// 发送应答报文send(sockfd, resp_str.c_str(), resp_str.size(),0);}
}
结果展示
之后通过浏览器访问我们的http服务,所获得的网页。
完整代码
main.cc 文件
// 服务器端
// 基于HTTP协议
#include "http.hpp"
#include <sys/wait.h>// 缓冲区大小
#define BUFFER_SIZE 4096// 定义一个回调方法,处理请求
void handle_request(int sockfd)
{char buffer[BUFFER_SIZE];// 读取请求报文ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1,0);if (n > 0){buffer[n] = 0;//for debug//std::cout<<buffer<<std::endl;Request req;// 将读取到的字符串反序列为请求对象req.Deserilaze(buffer);// 构建应答报文Response resp;//获取客户端想要访问的资源文件resp.SetTargetFile(req.GetUri());//for debug//std::cout<<"##############################"<<std::endl;//std::cout<<req.GetUri()<<std::endl;//std::cout<<"##############################"<<std::endl;// 将目标文件内容填写到正问部分resp.SetText();resp._version = "HTTP/1.1";resp._code = 200; // successresp._desc = "OK";// 反序列化std::string resp_str = resp.Serilaze();// 发送应答报文send(sockfd, resp_str.c_str(), resp_str.size(),0);}
}
const int gbacklog = 8;
int main(int argc, char *argv[])
{// 1,创建套接字int listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd < 0){std::cerr << "创建监听套接字失败" << std::endl;exit(1);}// 从命令行参数中获取端口号uint16_t port = std::stoi(argv[1]);// 填写sockaddr_in结构体,注意主机序列转化为网络字节序struct sockaddr_in addr;int addrlen = sizeof(addr);addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = INADDR_ANY;// 2,绑定端口号和ip地址int n = bind(listenfd, (struct sockaddr *)&addr, sizeof(addr));if (n < 0){std::cerr << "绑定失败" << std::endl;exit(2);}// 3,开始监听int s = listen(listenfd, gbacklog);if (s < 0){std::cerr << "监听失败" << std::endl;exit(3);}// 4,获取连接,处理连接while (true){int sockfd = accept(listenfd, (struct sockaddr *)&addr, (socklen_t *)&addrlen);if (n < 0){std::cerr << "获取连接失败" << std::endl;continue; // 继续获取}// 创建子进程处理请求pid_t id = fork();if (id == 0){// 子进程// 关闭不需要的文件描述符close(listenfd);if (fork() > 0)exit(0); // 子进程退出// 孙子进程 处理请求handle_request(sockfd);// 孙子进程退出exit(0);}else if (id > 0){// 父进程// 关闭不需要的文件描述符close(sockfd);pid_t rid=::waitpid(id,nullptr,0);(void)rid;}else{std::cerr << "创建子进程失败" << std::endl;}}return 0;
}
http.hpp文件
#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <unordered_map>
#include <sstream>
#include <fstream>const std::string gspace = " ";
const std::string glinespace = "\r\n";
const std::string glinesep = ": ";
// web根目录
const std::string webroot = "./wwwroot";
// 默认访问的首页
const std::string homepage = "index.html";// http协议
// 包含请求和应答
// 请求
class Request
{
public:Request(){}~Request(){}// 反序列化接口bool Deserilaze(std::string bigstr){std::string reqline;// 读取第一行,第一行的末尾是"\r\n"// 所以在字符串中找到"\r\n"的位置,截取前面部分即可auto pos = bigstr.find(glinespace);if (pos == std::string::npos)return false; // 不包含完整的请求// 获取到第一行的内容reqline = bigstr.substr(0, pos);// 将第一行进行反序列化std::stringstream ss(reqline);ss >> _method >> _uri >> _version;if (_uri == "/") // 表示要访问的资源就是web根目录下的首页_uri = webroot + _uri + homepage;else_uri = webroot + _uri; // 表示要访问特定路径下的资源// 删除第一行bigstr.erase(0, pos + glinespace.size());return true;}std::string GetUri(){return _uri;}private:std::string _method; // 请求方法std::string _uri; // uristd::string _version; // http版本// 请求报头std::unordered_map<std::string, std::string> _headers;// 空行std::string _blankline;// 正文std::string _text;
};// 应答
class Response
{
public:Response():_blankline(glinespace){}~Response(){}// 序列化std::string Serilaze(){// 状态行std::string status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;// 响应报头std::string resp_header;for (auto &header : _headers){std::string line = header.first + glinesep + header.second + glinespace;resp_header += line;}return status_line + resp_header + _blankline + _text;}// 设置想要访问的资源文件void SetTargetFile(const std::string file){_targetfile = file;}//将目标文件填写入正文部分void SetText(){std::ifstream in(_targetfile);if(!in.is_open()){return ;}std::string line;while(std::getline(in,line)){_text+=line;}in.close();}public:std::string _version; // http版本int _code; // 退出码std::string _desc; // 描述退出码的退出信息// 应答报头std::unordered_map<std::string, std::string> _headers;// 空行std::string _blankline;// 正文std::string _text;// 文件,用来填充正文std::string _targetfile;
};
makefile
myhttp:main.ccg++ -o $@ $^ -std=c++17
.PHONY:clean
clean:rm -f myhttp
相关测试网页(html形式)
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Default Home Page</title><style>body {font-family: Arial, sans-serif;margin: 0;padding: 0;background-color: #f4f4f4;color: #333;}header {background-color: #007bff;color: #fff;padding: 10px 20px;text-align: center;}nav {background-color: #343a40;padding: 10px 0;}nav a {color: #fff;text-decoration: none;padding: 10px 20px;display: inline-block;}nav a:hover {background-color: #5a6268;}.container {padding: 20px;}.welcome {text-align: center;margin-bottom: 20px;}.welcome h1 {margin: 0;}.content {background-color: #fff;padding: 20px;border-radius: 8px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);}footer {background-color: #343a40;color: #fff;text-align: center;padding: 10px 0;position: fixed;width: 100%;bottom: 0;}</style>
</head>
<body><header><h1>Welcome to Our Website</h1></header><nav><a href="#">Home</a><a href="Login.html">Login</a> <!-- 跳转到登录页面 --><a href="Register.html">Register</a> <!-- 跳转到注册页面 --><a href="#">About</a><a href="#">Contact</a></nav><div class="container"><div class="welcome"><h1>Welcome to Our Default Home Page</h1><p>This is a simple default home page template.</p></div><div class="content"><h2>Introduction</h2><p>This is a basic HTML template for a default home page. It includes a header, navigation bar, a welcome section, and a content area. You can customize this template to suit your needs.</p></div></div><footer><p>© 2025 Your Company Name. All rights reserved.</p></footer>
</body>
</html>
Login.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Login Page</title><style>body {font-family: Arial, sans-serif;background-color: #f4f4f4;display: flex;justify-content: center;align-items: center;height: 100vh;margin: 0;}.login-container {background-color: #fff;padding: 20px;border-radius: 8px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);width: 300px;text-align: center;}.login-container h2 {margin-bottom: 20px;}.form-group {margin-bottom: 15px;}.form-group label {display: block;margin-bottom: 5px;text-align: left;}.form-group input {width: 100%;padding: 10px;border: 1px solid #ccc;border-radius: 4px;}.form-group input[type="submit"] {background-color: #007bff;color: #fff;border: none;cursor: pointer;}.form-group input[type="submit"]:hover {background-color: #0056b3;}</style>
</head>
<body><div class="login-container"><h2>Login</h2><form action="/login" method="post"><div class="form-group"><label for="username">Username</label><input type="text" id="username" name="username" required></div><div class="form-group"><label for="password">Password</label><input type="password" id="password" name="password" required></div><div class="form-group"><input type="submit" value="Login"></div></form></div>
</body>
</html>
Register.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Register Page</title><style>body {font-family: Arial, sans-serif;background-color: #f4f4f4;display: flex;justify-content: center;align-items: center;height: 100vh;margin: 0;}.register-container {background-color: #fff;padding: 20px;border-radius: 8px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);width: 350px;text-align: center;}.register-container h2 {margin-bottom: 20px;}.form-group {margin-bottom: 15px;}.form-group label {display: block;margin-bottom: 5px;text-align: left;}.form-group input {width: 100%;padding: 10px;border: 1px solid #ccc;border-radius: 4px;}.form-group input[type="submit"] {background-color: #28a745;color: #fff;border: none;cursor: pointer;}.form-group input[type="submit"]:hover {background-color: #218838;}</style>
</head>
<body><div class="register-container"><h2>Register</h2><form action="/register" method="post"><div class="form-group"><label for="username">Username</label><input type="text" id="username" name="username" required></div><div class="form-group"><label for="email">Email</label><input type="email" id="email" name="email" required></div><div class="form-group"><label for="password">Password</label><input type="password" id="password" name="password" required></div><div class="form-group"><label for="confirm-password">Confirm Password</label><input type="password" id="confirm-password" name="confirm-password" required></div><div class="form-group"><input type="submit" value="Register"></div></form></div>
</body>
</html>
相关文章:
【Linux网络编程】应用层协议HTTP(实现一个简单的http服务)
目录 前言 一,HTTP协议 1,认识URL 2,urlencode和urldecode 3,HTTP协议请求与响应格式 二,myhttp服务器端代码的编写 HTTP请求报文示例 HTTP应答报文示例 代码编写 网络通信模块 处理请求和发送应答模块 结…...
深度解析之算法之分治(快排)
44.颜色分类 题目链接 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 必须在不使用库内置…...
【金仓数据库征文】-金仓数据库性能调优 “快准稳” 攻略:实战优化,让数据处理飞起来
我的个人主页 我的专栏: 人工智能领域、java-数据结构、Javase、C语言,希望能帮助到大家!!! 点赞👍收藏❤ 目录 一、KingbaseES金仓数据库简介二、快速入门:金仓数据库下载与安装指南三、“快”…...
DPIN河内AI+DePIN峰会:共绘蓝图,加速构建去中心化AI基础设施新生态
近日,一场聚焦前沿科技融合的盛会——AIDePIN峰会在越南河内成功举办。此次峰会由DPIN、QPIN及42DAO等Web3领域的创新项目联合组织,汇聚了众多Web3行业领袖、技术专家与社区成员。峰会于2025年4月19日举行,其核心议题围绕去中心化物理基础设施…...
vscode和git 踩坑
git init经常 在 vscode push错误问题: 正确姿势:先 GitHub 上建仓库 → git clone 拉到本地 → 再用 VSCode 打开编辑 ❌ 不是:VSCode 里 git init → 再去 GitHub 选个仓库绑定 举个对比 操作流程是否推荐后果GitHub 创建仓库 → git clone → 用 VSC…...
C++11介绍
目录 一、C11的两个小点 1.1、decltype 1.2、nullptr 二、列表初始化 2.1、C98传统的{} 2.2、C11中的{} 2.3、C11中的std::initializer_list 三、右值引用和移动语义 3.1、左值和右值 3.2、左值引用和右值引用 3.3、引用延长生命周期 3.4、左值和右值的参数匹配 3…...
AI数字人:繁荣背后的伦理困境与法律迷局(8/10)
摘要:本文深入剖析 AI 数字人从虚拟走向现实的历程,阐述其融合多技术实现从静态到动态交互的跨越,爆发式应用于各领域带来的商业价值与社会影响,同时直面由此引发的伦理法律挑战,包括身份认同、数据隐私、责任归属及权…...
SOLID 原则在单片机环境下的 C 语言实现示例,结合嵌入式开发常见场景进行详细说明
1. 单一职责原则 (SRP) 定义:一个模块(函数/文件)只负责一个功能。 示例:传感器数据采集与处理分离 // SensorAdc.h - 仅负责ADC原始数据采集 typedef struct { uint16_t (*ReadRaw)(void); // 原始数据读取接口 } SensorAdc; // SensorProcessor.h - 仅负责数据处理…...
RT Thread 发生异常时打印输出cpu寄存器信息和栈数据
打印输出发生hardfault时,当前栈十六进制数据和cpu寄存器信息 在发生 HardFault 时,打印当前栈的十六进制数据和 CPU 寄存器信息是非常重要的调试手段。以下是如何实现这一功能的具体步骤和示例代码。 1. 实现 HardFault 处理函数 我们需要在 HardFault 中捕获异常上下文,…...
SQL 函数进行左边自动补位fnPadLeft和FORMAT
目录 1.问题 2.解决 方式1 方式2 3.结果 1.问题 例如在SQL存储过程中,将1 或10 或 100 长度不足的时候,自动补足长度。 例如 1 → 001 10→ 010 100→100 2.解决 方式1 SELECT FORMAT (1, 000) AS FormattedNum; SELECT FORMAT(12, 000) AS Form…...
Unity中数据和资源加密(异或加密,AES加密,MD5加密)
在项目开发中,始终会涉及到的一个问题,就是信息安全,在调用接口,或者加载的资源,都会涉及安全问题,因此就出现了各种各样的加密方式。 常见的也是目前用的最广的加密方式,分别是:DES、3DES、AES、MD5、XOR(异或) 其中DES、3DES、AES、MD5用在数据加密中偏多,特别是…...
C++初窥门径
const关键字 一、const关键字 修饰成员变量 常成员变量:必须通过构造函数的初始化列表进行初始化,且初始化后不可修改。 示例: class Student { private: const int age; // 常成员变量 public: Student(string name, int age) : age(ag…...
Spring知识点总结
目录 1.什么是spring?你对spring的理解? 2.spring的优缺点? 3.解释一下IOC和AOP? 4.IOC和DI的区别? 5.spring中管理对象注入的方式? 6.自动注入的注解有哪些? 声明bean的注解 Bean的生命…...
Oracle_开启归档日志和重做日志
在Oracle中,类似于MySQL的binlog的机制是归档日志(Archive Log)和重做日志(Redo Log) 查询归档日志状态 SELECT log_mode FROM v$database; – 输出示例: – LOG_MODE – ARCHIVELOG (表示已开启) – NO…...
【金仓数据库征文】-数据库界新兴前列者,本篇带你速懂金仓数据库!
最近写课程设计、搞毕设是不是被数据库折腾到崩溃?动不动就报错、数据迁移还超麻烦!今天挖到个宝藏 —— 国产金仓数据库 KingbaseES,操作超简单,还自带 “翻译器” 帮你迁移数据!性能强还稳定,关键完全免费…...
人工智能与机器学习,谁是谁的子集 —— 再谈智能的边界与演进路径
人工智能(Artificial Intelligence, AI)作为当代最具影响力的前沿技术之一,常被大众简化为 “深度学习” 或 “大模型” 等标签。然而,这种简化认知往往掩盖了AI技术内部结构的复杂性与多样性。事实上,AI并非单一方法的…...
Linux进程学习【进程状态】
🌼🌼前言:在操作系统中,进程是最基本的资源管理单位,而操作系统通过精确管理这些进程的状态来确保系统能够高效运行。进程的状态不仅仅是操作系统设计的一部分,它对系统的性能、稳定性以及资源的分配起着至…...
用 ESP32 模拟 Wiegand 刷卡器:开发门禁系统必备的小工具
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...
什么是 MCP?与 AI Agent 的关系是什么?
首先先回答一下什么是MCP? 如果你经常使用像Claude这样的大语言模型,你可能已经注意到它们虽然强大,但有时候也有局限性,比如无法获取实时信息或访问特定工具。 模型上下文协议(Model Context Protocol,简…...
Python ZIP文件操作全解析:从基础压缩到高级技巧
目录 一、ZIP文件操作基础三板斧 1.1 创建压缩包 1.2 解压操作 1.3 文件遍历与信息获取 二、进阶技巧:让压缩更智能 2.1 加密压缩实战 2.2 增量更新策略 2.3 性能优化技巧 三、高级场景解决方案 3.1 分卷压缩实现 3.2 跨平台路径处理 3.3 异常处理最佳实…...
Linux:进程的等待
当以一个进程结束时,它会变成僵尸进程,这个僵尸进程如果不处理,就会一直占用CPU资源,如果父进程要回收这个进程会通过进程等待的方式处理,回收子进程只会,会得到进程的退出信息 进程等待 父进程通过进程等…...
玉米产量遥感估产系统的开发实践(持续迭代与更新)
项目地址:项目首页 - maize_yield_estimation:玉米估产的flaskvue项目 - GitCode 开发中,敬请期待。。。 以下是预先写的提纲,准备慢慢补充 一、项目背景与工程目标 业务需求分析 农业遥感估产的行业痛点(数据分散、模型精度不足…...
Python解析地址中省市区街道
Python解析地址中省市区街道 1、效果 输入:海珠区沙园街道西基村 输出: 2、导入库 pip install jionlp3、示例代码 import jionlp as jiotext 海珠区沙园街道西基村 res jio.parse_location(text, town_villageTrue) print(res)...
论文学习:《聚类矩阵正则化指导的层次图池化》
原文标题:Clustering matrix regularization guided hierarchical graph pooling 原文链接:https://www.sciencedirect.com/science/article/abs/pii/S0950705125001558 图池化技术大致可以分为两类:平面图池化和层次图池化。后者通过迭代粗化…...
【金仓数据库征文】- 国产化迁移实战:从Oracle到KingbaseES的平滑过渡
文章目录 引言:国产数据库的崛起与迁移需求一、兼容性架构设计与配置优化1.1 Oracle兼容模式的核心实现1.2 潜在语法差异的深度处理1.3 环境预配置关键技术1.3.1 用户与模式映射1.3.2 字符集与日期格式 1.4 深度兼容模式配置1.4.1 语法兼容开关1.4.2 数据类型映射策…...
「零配置陷阱」:现代全栈工具链的复杂度管控实践
一、工具链膨胀的「死亡螺旋」 2024年典型全栈项目的初始化噩梦: $ npm create vitelatest ✔ Project name: … demo ✔ Select a framework: › React ✔ Select a variant: › TypeScript SWC ✔ Install shadcn/ui? … Yes ✔ Add Storybook? … Yes ✔ Co…...
浅析锁的应用与场景
锁的应用与场景:从单机到分布式 摘要:在多线程和分布式系统中,“锁”是避免资源竞争、保障数据一致性的核心机制。但你真的了解锁吗?什么时候该用锁?用哪种锁?本文通过通俗的比喻和代码示例,带…...
图论---Kruskal(稀疏图)
O( m * log n )。 1,将所有边按权重从小到大排序,调用系统的sort() 2,枚举每条边的 a , b ,权重 if(a、b 不联通) 就将这条边加入集合中 // 最小生成树 —Kruskal算法(稀疏图) #include<iostream> #include<algorithm> using …...
MySQL 从入门到精通:第二篇 - 数据类型、约束与索引
1. MySQL数据类型详解 数值类型 整数类型 -- 常用整数类型及范围 CREATE TABLE integer_types (tiny_col TINYINT, -- 1字节,有符号(-128~127),无符号(0~255)small_col SMALLINT, -- 2字节,有符号(-32768~32767),无符号(0~65535)medium_col MEDIUMINT,...
基于AI技术的高速公路交通引流系统设计与应用研究
基于AI技术的高速公路交通引流系统设计与应用研究 1. 研究背景与意义 1.1 交通系统演化脉络 1.1.1 发展阶段划分 机械化时代(1950-1990):固定式信号控制信息化时代(1991-2010):SCATS/SCOOT系统智能化时代…...
n8n 中文系列教程_09. 从原始需求到精准实现:n8n节点选择指南
在自动化工作流工具n8n中,正确选择和使用节点是高效实现需求的关键。本文将从需求分析入手,逐步解析触发节点与执行节点的区别,梳理n8n的节点分类逻辑,并揭示外部服务节点的本质,帮助您精准匹配需求与实现方案。无论您…...
P19:Inception v1算法实战与解析
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 一、模型结构 Inception V1 的主要特点是在一个网络中同时使用不同大小的卷积核(1x1、3x3、5x5)和池化操作来提取多尺度特征。以下是…...
day32 学习笔记
文章目录 前言一、霍夫变换二、标准霍夫变换三、统计概率霍夫变换四、霍夫圆变换 前言 通过今天的学习,我掌握了霍夫变换的基本原本原理及其在OpenCV中的应用方法 一、霍夫变换 霍夫变换是图像处理中的常用技术,主要用于检测图像中的直线,圆…...
2025时间序列都有哪些创新点可做——总结篇
作为AI和数据科学的核心方向之一,时间序列在2025年依然保持着强劲的发展势头,稳站各大顶会顶刊投稿主题前列。 关于它的研究,目前在结合传统统计方法和深度学习的基础上,已延伸至频域等数理工具与神经网络的交叉创新。同时针对垂…...
头歌实训之索引
🌟 各位看官好,我是maomi_9526! 🌍 种一棵树最好是十年前,其次是现在! 🚀 今天来学习C语言的相关知识。 👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更…...
通讯的基础概念:涵盖串行通信、并行通信、TCP、UDP、Socket 等关键概念和技术
一、通信基础概念 1. 串行通信与并行通信 串行通信 定义:通过一条线路逐位传输数据,每个字节包含起始位、数据位、校验位和停止位。特点: 传输稳定,但速度较慢(因逐位传输)。常用接口:RS-232、…...
Uni-App 多端电子合同开源项目介绍
项目概述 本项目是一款基于 uni-app框架开发的多端电子合同管理平台,旨在为企业及个人用户提供高效、安全、便捷的电子合同签署与管理服务。项目创新性地引入了 “证据链”与“非证据链”两种签署模式,满足不同场景下的签署需求,支持多种签署…...
一个非常快速的 Latex 入门教程【Part 1】
目录 1.LaTex简介 2.LaTex 中最基础的格式化命令 2.1加粗,斜体,下划线,添加新段落 2.2文档分节 2.3 图片 2.4 LaTeX 中列表的创建 无序列表 有序列表 2.5对数学公式的排版 2.6表格 1.LaTex简介 LaTex的主要优势是它会将文…...
用Obsidian四个插件打造小说故事关联管理系统:从模板到图谱的全流程实践
用Obsidian四个插件打造小说故事关联管理系统:从模板到图谱的全流程实践 一、前言:为什么需要故事关联管理系统 在小说创作中,复杂的人物关系、交错的情节线和多维的世界观常导致创作混乱。本文将通过 Dataview(数据查询…...
C++ 日志系统实战第三步:熟悉掌握各种设计模式
全是通俗易懂的讲解,如果你本节之前的知识都掌握清楚,那就速速来看我的项目笔记吧~ 相关技术知识补充,也是最后的补充知识了~ 下文将加入项目代码编写! 目录 设计模式 单例模式 饿汉模式 懒汉模式 工厂模式 简单…...
[ESP-IDF]:esp32-camera 使用指南 ESP32S3-OV2640 用例测试
【核知坊】:释放青春想象,码动全新视野。 我们希望使用精简的信息传达知识的骨架,启发创造者开启创造之路!!! 内容摘要:esp32-camera 组件为 ESP32 系列 SoC 提供了兼容的图…...
在统信UOS/麒麟Kylin OS中创建网页桌面快捷方式
在统信UOS/麒麟Kylin OS中创建网页桌面快捷方式 本文将详细介绍如何在统信UOS或麒麟KYLINOS中使用命令行创建一个网页桌面快捷方式,以方便构建云桌面模板及镜像模板。欢迎大家浏览、分享和转发!请关注我以获取更多技术分享。 1. 查看系统信息 首先&am…...
SQLite 是什么?
📌 一、SQLite 是什么? SQLite 是一个轻量级、嵌入式数据库,意思是它直接集成在你的 App 内部,不需要单独安装数据库服务端。 ✅ 特点: 特点说明本地使用所有数据保存在手机内部存储文件形式数据以 .db 文件形式存储…...
恒创科技「香港大带宽云」新老用户专享实例及热门配置
全球化数字浪潮下,高带宽应用正深度重构各行业运营模式——从跨境电商、流媒体与视频点播,到在线游戏与云游戏加速,涵盖所有高并发、强交互的业务场景。在此背景下,企业对高性能 IT 基础架构的需求持续升级,以此来支持…...
fpga系列 HDL:verilog latch在fpga中的作用 避免latch的常见做法
目录 Latch在FPGA中的作用Quartus中有关latch的警告⚠避免Latch的常见做法1. if-else 语句未覆盖所有条件生成Latch的代码:修复后的代码: 2. case语句未覆盖所有分支生成Latch的代码:修复后的代码: 3. 组合逻辑中缺少默认赋值生成…...
java配置
环境变量...
解决虚拟主机ping不通本地主机问题
win11 1 问题 虚拟主机和本地主机在同一网段。 2 解决方案 以win11为例: 设置 -> 网络和 Internet -> 高级网路设置 -> Windows 防火墙 -> 高级设置 -> 入站规则 -> 新建规则 需要设置:规则类型、 协议和端口、名称,其…...
Move Registry 发布,实现 Sui 的超级互操作性
Move Registry(MVR)的到来对 Sui 来说是一件大事。MVR 是一个功能齐全的链上包管理系统,提升了整个生态的可发现性、可信度和互操作性。Sui 本身就是最具互操作性的链之一,凭借 Move 语言和可编程交易区块(PTBs&#x…...
【Linux】gdb工具,Linux 下程序调试的 “透视眼”
目录 调试代码调试注意事项gdb和Cgdb调试命令汇总行号显示断点设置查看断点信息删除断点开启 / 禁用断点运行 / 调试逐过程和逐语句打印 / 追踪变量指定行号跳转强制执行函数 补充命令watchset var 替换变量值条件断点 end 调试代码 这是本次调试要用的代码 1 #include <st…...
脚本分享:快速作图对比wannier拟合能带python脚本
本脚本通过Python实现电子能带结构数据的快速作图,能够从两个不同的数据文件(BAND.dat 和 wannier90_band.dat)中提取有效数据,并在同一坐标系下绘制对比图。 准备工作:使用VASPKIT处理获得能带数据BAND.datÿ…...