【Linux网络】构建HTTP响应与请求处理系统 - HttpResponse从理解到实现
📢博客主页:https://blog.csdn.net/2301_779549673
📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨
文章目录
- 🏳️🌈一、HttpResponse 类
- 1.1 基本结构
- 1.2 构造函数、析构函数
- 1.3 添加属性成员函数
- 1.4 序列化函数
- 1.5 请求处理回调函数
- 1.6 HttpServer.hpp 整体代码
- 🏳️🌈二、模拟前端
- 2.1 404.html
- 2.2 default.html
- 2.3 login.html
- 2.4 register.html
- 2.5 success.html
- 🏳️🌈三、测试
- 3.1 默认网站
- 3.2 登录
- 3.3 404
- 👥总结
11111111
11111111
11111111
11111111
**** 11111111
🏳️🌈一、HttpResponse 类
1.1 基本结构
HttpResponse类
成员变量除了跟HttpRequest类
一样的基本格式状态行,应答报头,空行和响应正文外;还包括基本属性版本,状态码,状态码描述,以及报头的KV结构;
成员函数包括增加状态码,报头和正文
class HttpResponse {
public:HttpResponse() {}void AddCode(int code);void AddHeader(const std::string& k, const std::string& v);void AddBodyText(const std::string& _body_text);std::string Serialize();~HttpResponse() {}private:// httpresponse base 属性std::string _version; // 版本int _status_code; // 状态码std::string _desc; // 状态码描述std::unordered_map<std::string, std::string> _headers_kv;// 基本的 httpresponse 的格式std::string _status_line; // 状态行std::vector<std::string> _rsp_heeaders; // 响应报头std::string _blank_line; // 空行std::string _rsp_body; // 响应正文
};
1.2 构造函数、析构函数
const static std::string _default_http_version = "HTTP/1.0"; // 初始版本
const static std::string _space_sep = " "; // 空格分隔符HttpResponse() : _version(_default_http_version), _blank_line(_base_sep) {}
~HttpResponse() {}
1.3 添加属性成员函数
- 添加状态码默认初始化状态码,并将状态码描述设置为OK
- 将传入的KV数据插入到 请求报头 的KV结构中
- 添加请求正文即可!
// 添加 状态码 和 状态码描述
void AddCode(int code) {_status_code = code;_desc = "OK";
}// 添加响应报头键值对
void AddHeader(const std::string& k, const std::string& v) {_headers_kv[k] = v;
}// 添加请求正文
void AddBodyText(const std::string& _body_text) { _rsp_body = _body_text; }
1.4 序列化函数
序列化即将结构化数据转化为字符串数据,主要有下面四个步骤:
1、构建状态行
2、构建报头
3、空行和正文(无需处理,空行已初始化,正文内容在KV结构中)
4、正式序列化
// 序列化响应报文
std::string Serialize() {// 1. 构建状态行_status_line = _version + _space_sep + std::to_string(_status_code) +_space_sep + _desc + _base_sep;// 2. 构建响应报头for (auto& header : _headers_kv) {_rsp_headers.push_back(header.first + _line_sep + header.second +_base_sep);}// 3. 构建空行(构造函数时已经处理好空行)// 4. 构建响应正文(需调用 AddBodyText 接口)// 5. 序列化响应报文std::string rsponsestr = _status_line;for (auto& line : _rsp_headers)rsponsestr += line;rsponsestr += _blank_line;rsponsestr += _rsp_body;return rsponsestr;
}
1.5 请求处理回调函数
上一篇文章中我们不是使用了 handler
这个处理回调函数,去看我们反序列化的请求报文,这一篇文章,我们不需要去查看请求报文了,而是将其进行处理,构建序列化的响应报文就行了
这里我们需要获取请求路径下的内容,将其返回,我们可以以二进制的方式打开指定路径,然后读取内容
std::string GetFileContent(const std::string& path) {std::ifstream in(path, std::ios::binary); // 以二进制方式打开文件if (!in.is_open())return std::string();in.seekg(0, in.end); // 将文件读取指针(也称为"get"指针)移动到文件的末尾int filesize =in.tellg(); // 获取当前文件读取指针的位置,即文件的总大小,单位字节in.seekg(0, in.beg); // 将文件读取指针移动到文件的开头std::string content;content.resize(filesize); // 调整 content 的大小为 filesizein.read((char*)content.c_str(),filesize); // 读取 filesize 字节的文件内容到 content 中in.close(); // 关闭文件return content;
}
然后就是处理得到的内容了,利用前面的 添加状态码方法
、添加报文键值对方法
,以及添加响应正文的方法
。最后将整个相应类对象序列化返回即可
std::string HandleRequest(std::string req) {std::cout << "------------------------------------" << std::endl;std::cout << req;HttpRequest req_obj;req_obj.Descrialize(req);std::string content = GetFileContent(req_obj.Path());if (content.empty())return std::string();HttpResponse rsp;rsp.AddCode(200);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddBodyText(content);return rsp.Serialize();
}
1.6 HttpServer.hpp 整体代码
#pragma once#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <fstream>#include "Log.hpp"using namespace LogModule;// const static std::string _base_sep = "\r\n"; // 默认具有外部链接,其他文件可通过 extern 引用。
const static std::string _base_sep = "\r\n"; // static 关键字使变量具有内部链接,仅当前翻译单元(源文件)可见。
const static std::string _line_sep = ": ";
const static std::string _prefix_path = "wwwroot"; // 默认前缀路劲
const static std::string _default_path = "default.html"; // 默认路径const static std::string _default_http_version = "HTTP/1.0"; // 初始版本
const static std::string _space_sep = " "; // 空格分隔符namespace HttpServer{class HttpRequest{private:// 获取一行信息std::string GetLine(std::string& reqstr){auto pos = reqstr.find(_base_sep);if(pos == std::string::npos) return "";std::string line = reqstr.substr(0, pos); // 截取一行有效信息reqstr.erase(0, pos + _base_sep.length()); // 删除有效信息和分隔符return line.empty() ? _base_sep : line; // 有效信息为空则返回分隔符,否则返回有效信息}// 解析请求行void PraseReqLine(){ // 以空格为分隔符,不断读取std::stringstream ss(_req_line);ss >> _method >> _url >> _version; _path += _url;// 处理url,如果是根目录,则返回默认路径if(_url == "/")_path += _default_path;}// 解析请求头void PraseHeader(){for(auto& header : _req_headers){auto pos = header.find(':');if(pos == std::string::npos)continue;std::string k = header.substr(0, pos);std::string v = header.substr(pos + _line_sep.size());if(k.empty() || v.empty()) continue;_headers_kv[k] = v;}}public:HttpRequest() : _blank_line(_base_sep), _path(_prefix_path) {}void Descrialize(std::string& reqstr){// 基本的反序列化_req_line = GetLine(reqstr); // 读取第一行请求行// 请求报头std::string header;do{header = GetLine(reqstr);// 如果既不是空,也不是空行,就是请求报头,加入到请求报头列表中if(header.empty()) break;else if(header == _base_sep) break;_req_headers.push_back(header);}while(true);// 正文if(!reqstr.empty())_req_body = reqstr;// 进一步反序列化请求行PraseReqLine();// 分割请求报头,获取键值对PraseHeader(); }void Print(){std::cout << "----------------------------------------" <<std::endl;std::cout << "请求行: ###" << _req_line << std::endl;std::cout << "请求报头: " << std::endl;for(auto& header : _req_headers){std::cout << "@@@" << header << std::endl;}std::cout << "空行: " << _blank_line << std::endl;std::cout << "请求体: " << _req_body << std::endl;std::cout << "Method: " << _method << std::endl;std::cout << "Url: " << _url << std::endl;std::cout << "Version: " << _version << std::endl;}std::string Url(){LOG(LogLevel::INFO) << "client want url : " << _url; return _url;}std::string Path(){LOG(LogLevel::INFO) << "client want path : " << _path; return _path;}~HttpRequest() {}private:std::string _req_line; // 请求行std::vector<std::string> _req_headers; // 请求报头std::string _blank_line; // 空行std::string _req_body; // 请求体std::string _method; // 请求方法std::string _path; // 资源路径std::string _url; // 请求urlstd::string _version; // 请求版本std::unordered_map<std::string, std::string> _headers_kv; // 存储每行报文的哈希表};class HttpResponse{public:HttpResponse() : _version(_default_http_version), _blank_line(_base_sep){}// 添加 状态码 和 状态码描述void AddCode(int code){_status_code = code;_desc = "OK";}// 添加响应报头键值对void AddHeader(const std::string& k, const std::string& v){_headers_kv[k] = v;}// 添加请求正文void AddBodyText(const std::string& _body_text){_rsp_body = _body_text;}// 序列化响应报文std::string Serialize(){// 1. 构建状态行_status_line = _version + _space_sep + std::to_string(_status_code) + _space_sep + _desc + _base_sep;// 2. 构建响应报头for(auto& header : _headers_kv){_rsp_headers.push_back(header.first + _line_sep + header.second + _base_sep);}// 3. 构建空行(构造函数时已经处理好空行)// 4. 构建响应正文(需调用 AddBodyText 接口)// 5. 序列化响应报文std::string rsponsestr = _status_line;for(auto& line : _rsp_headers)rsponsestr += line;rsponsestr += _blank_line;rsponsestr += _rsp_body;return rsponsestr;}~HttpResponse(){}private:// httpresponse base 属性std::string _version; // 版本int _status_code; // 状态码std::string _desc; // 状态码描述std::unordered_map<std::string, std::string> _headers_kv;// 基本的 httpresponse 的格式std::string _status_line; // 状态行std::vector<std::string> _rsp_headers; // 响应报头std::string _blank_line; // 空行std::string _rsp_body; // 响应正文};class HttpHandler{public:HttpHandler(){}std::string HandleRequest(std::string req){std::cout << "------------------------------------" << std::endl;std::cout << req;HttpRequest req_obj;req_obj.Descrialize(req);std::string content = GetFileContent(req_obj.Path());if(content.empty())return std::string();HttpResponse rsp;rsp.AddCode(200);rsp.AddHeader("Content-Length", std::to_string(content.size()));rsp.AddBodyText(content);return rsp.Serialize();}std::string GetFileContent(const std::string& path){std::ifstream in(path, std::ios::binary); // 以二进制方式打开文件if(!in.is_open()) {LOG(LogLevel::ERROR) << "open path " << path << " failed";return std::string();}in.seekg(0, in.end); // 将文件读取指针(也称为"get"指针)移动到文件的末尾int filesize = in.tellg(); // 获取当前文件读取指针的位置,即文件的总大小,单位字节in.seekg(0, in.beg); // 将文件读取指针移动到文件的开头std::string content;content.resize(filesize); // 调整 content 的大小为 filesizein.read((char*)content.c_str(), filesize); // 读取 filesize 字节的文件内容到 content 中in.close(); // 关闭文件return content;}~HttpHandler(){}};
}
🏳️🌈二、模拟前端
这里我们建立使用4个界面模拟一下浏览器的界面,因为博主并不擅长,所以就一笔带过了
这里我们使用5个前端界面,在这个目录下创建一个
wwwroot
的文件夹,将相关的html
文件都放在这里面,我在默认界面中放了3张图片,存储在wwwroot
界面的image
文件夹中,这个只要命名对就行了,也就是1.jpg
这样,具体什么照片都行,不过要是jpg格式的
2.1 404.html
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>404 页面未找到</title><style>body {font-family: Arial, sans-serif;background-color: #f7f7f7;margin: 0;padding: 0;}.container {max-width: 600px;margin: 50px auto;padding: 20px;background-color: #fff;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);text-align: center;}h1 {color: #333;font-size: 2.5em;margin-bottom: 20px;}p {color: #666;font-size: 1.2em;line-height: 1.6;margin-bottom: 30px;}a {display: inline-block;padding: 10px 20px;background-color: #007bff;color: #fff;text-decoration: none;border-radius: 5px;font-size: 1.1em;}a:hover {background-color: #0056b3;}</style>
</head>
<body><div class="container"><h1>404 页面未找到</h1><p>抱歉,您请求的页面不存在。可能是链接错误或页面已被删除。</p><a href="/">返回首页</a></div>
</body>
</html>
2.2 default.html
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>简单电商网站</title><style>body {font-family: Arial, sans-serif;margin: 0;padding: 0;background-color: #f7f7f7;}.header {background-color: #333;color: #fff;padding: 10px 20px;display: flex;justify-content: space-between;align-items: center;}.header h1 {margin: 0;font-size: 2em;}.header nav ul {list-style: none;margin: 0;padding: 0;display: flex;}.header nav ul li {margin-left: 20px;}.header nav ul li a {color: #fff;text-decoration: none;font-size: 1.2em;}.header nav ul li a:hover {text-decoration: underline;}.main {padding: 20px;}.product-grid {display: grid;grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));gap: 20px;}.product-card {background-color: #fff;padding: 10px;border: 1px solid #ddd;border-radius: 5px;text-align: center;}.product-card img {max-width: 100%;height: auto;border-radius: 5px;}.product-card h3 {margin: 10px 0;font-size: 1.2em;}.product-card p {color: #666;font-size: 0.9em;margin-bottom: 10px;}.product-card button {padding: 5px 10px;background-color: #007bff;color: #fff;border: none;border-radius: 5px;cursor: pointer;font-size: 1em;}.product-card button:hover {background-color: #0056b3;}.footer {background-color: #333;color: #fff;padding: 10px 20px;text-align: center;}</style>
</head>
<body><header class="header"><h1>简单电商网站</h1><nav><ul><li><a href="#">首页</a></li><li><a href="#">产品分类</a></li><li><a href="/login.html">登录</a></li><li><a href="/register.html">注册</a></li></ul></nav></header><main class="main"><h2>热门产品</h2><div class="product-grid"><div class="product-card"><img src="/image/1.jpg" alt="产品1"><h3>产品1</h3><p>这是产品1的描述信息。</p><button>加入购物车</button></div><div class="product-card"><img src="/image/2.jpg" alt="产品2"><h3>产品2</h3><p>这是产品2的描述信息。</p><button>加入购物车</button></div><div class="product-card"><img src="/image/3.jpg" alt="产品3"><h3>产品3</h3><p>这是产品3的描述信息。</p><button>加入购物车</button></div><!-- 可以继续添加更多产品卡片 --></div></main><footer class="footer"><p>版权所有 © 2025 简单电商网站</p></footer>
</body>
</html>
2.3 login.html
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>登录页面</title><style>body {font-family: Arial, sans-serif;background-color: #f7f7f7;margin: 0;padding: 0;}.login-container {width: 300px;margin: 100px auto;padding: 20px;background-color: #fff;border: 1px solid #ddd;border-radius: 5px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);}.login-container h2 {text-align: center;margin-bottom: 20px;}.login-container form {display: flex;flex-direction: column;}.login-container form label {margin-bottom: 5px;}.login-container form input[type="text"],.login-container form input[type="password"] {padding: 10px;margin-bottom: 10px;border: 1px solid #ddd;border-radius: 5px;}.login-container form button {padding: 10px;background-color: #007bff;color: #fff;border: none;border-radius: 5px;cursor: pointer;}.login-container form button:hover {background-color: #0056b3;}.register-link {text-align: center;margin-top: 20px;}.register-link a {color: #007bff;text-decoration: none;}.register-link a:hover {text-decoration: underline;}</style>
</head>
<body><div class="login-container"><h2>登录</h2><!-- http://8.137.19.140:8999/login --><form action="/login" method="POST"><label for="username">用户名:</label><input type="text" id="username" name="username" required><label for="password">密码:</label><input type="password" id="password" name="password" required><button type="submit">登录</button></form><div class="register-link">没有账号?<a href="/register.html">立即注册</a></br><a href="/">回到首页</a></div></div>
</body>
</html>
2.4 register.html
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>注册页面</title><style>body {font-family: Arial, sans-serif;background-color: #f7f7f7;margin: 0;padding: 0;}.register-container {width: 300px;margin: 100px auto;padding: 20px;background-color: #fff;border: 1px solid #ddd;border-radius: 5px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);}.register-container h2 {text-align: center;margin-bottom: 20px;}.register-container form {display: flex;flex-direction: column;}.register-container form label {margin-bottom: 5px;}.register-container form input[type="text"],.register-container form input[type="password"],.register-container form input[type="email"] {padding: 10px;margin-bottom: 10px;border: 1px solid #ddd;border-radius: 5px;}.register-container form button {padding: 10px;background-color: #007bff;color: #fff;border: none;border-radius: 5px;cursor: pointer;}.register-container form button:hover {background-color: #0056b3;}.login-link {text-align: center;margin-top: 20px;}.login-link a {color: #007bff;text-decoration: none;}.login-link a:hover {text-decoration: underline;}</style>
</head>
<body><div class="register-container"><h2>注册</h2><form action="/register" method="post"><label for="username">用户名:</label><input type="text" id="username" name="username" required><label for="email">邮箱:</label><input type="email" id="email" name="email" required><label for="password">密码:</label><input type="password" id="password" name="password" required><label for="confirm-password">确认密码:</label><input type="password" id="confirm-password" name="confirm-password" required><button type="submit">注册</button></form><div class="login-link">已有账号?<a href="/login.html">立即登录</a><br/><a href="/">回到首页</a></div></div>
</body>
</html>
2.5 success.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>登录成功</title><style>body {font-family: Arial, sans-serif;text-align: center;margin-top: 50px;}.message {font-size: 20px;color: green;}.countdown {font-size: 24px;font-weight: bold;margin-top: 20px;}</style>
</head>
<body><div class="message">登录成功!</div><div class="countdown" id="countdown">5秒后自动跳转到首页</div><script>// 设置倒计时时间(秒)let countdownTime = 5;// 获取倒计时显示元素const countdownElement = document.getElementById('countdown');// 倒计时函数const countdown = () => {countdownElement.textContent = `${countdownTime}秒后自动跳转到首页`;countdownTime--;if (countdownTime < 0) {// 倒计时结束,跳转到首页window.location.href = 'http://8.137.19.140:8888'; // 替换为你的首页地址}};// 每秒调用一次倒计时函数setInterval(countdown, 1000);</script>
</body>
</html>
🏳️🌈三、测试
3.1 默认网站
我们直接在服务器上运行我们自己写的服务端,然后再使用浏览器输入响应的网址的端口号,就看到这里有提示 客户请求进入 default.html
然后后面逐渐访问响应的照片,图片会加载出来
3.2 登录
点击右上角的登录,发现页面直接跳转到我们设置的 login.html
3.3 404
当我们在网址上输入 404.html 就会这样提示,因此我们可以在设置网址时,对不合规操作全部实现跳转到这个界面的接口
👥总结
本篇博文对 【Linux网络】构建HTTP响应与请求处理系统 - HttpResponse从理解到实现 做了一个较为详细的介绍,不知道对你有没有帮助呢
觉得博主写得还不错的三连支持下吧!会继续努力的~
相关文章:
【Linux网络】构建HTTP响应与请求处理系统 - HttpResponse从理解到实现
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
识破养生假象,拥抱科学健康
在这个全民热衷养生的时代,各种养生理念与方法如潮水般涌来。但其中不少是迷惑大众的 “烟雾弹”,只有识破这些养生假象,我们才能踏上真正的健康之路。 不少人觉得,养生就得靠保健品 “撑腰”。市面上,各类宣称具有…...
设计一个关键字统计程序:利用HashMap存储关键字统计信息,对用户输入的关键字进行个数统计。
思路分析 首先,在KeywordCounter类中,定义了一个包含所有Java关键字的字符串数组KEYWORDS,用于存储所有关键字。然后创建了一个Scanner对象input,用于从标准输入读取用户的输入。接下来创建了一个StringBuilder对象sb,…...
Python文件操作及数据库交互(Python File Manipulation and Database Interaction)
Python文件操作及数据库的交互 在实际开发中,文件操作与数据库交互是非常常见的任务。Python作为一种高效且灵活的编程语言,不仅提供了丰富的文件操作功能,还通过多种库与数据库进行高效交互。本文将详细介绍如何使用Python进行文件操作&…...
Eigen稀疏矩阵类 (SparseMatrix)
1. SparseMatrix 核心属性与初始化 模板参数 cpp SparseMatrix<Scalar, Options, StorageIndex> Scalar:数据类型(如 double, float)。 Options:存储格式(默认 ColMajor,可选 RowMajor࿰…...
【运维】Windows 与 Linux 中实时查看日志的命令对比详解(tail -f)
🔍 Windows 与 Linux 中实时查看日志的命令对比详解(tail -f) 在日常开发、调试、部署过程中,实时查看日志文件的更新内容是非常常见的需求。尤其是在排查后端服务问题、守护进程行为、系统异常等场景下,查看实时日志…...
巧用 Element - UI 实现图片上传按钮的智能隐藏
引言 在前端开发中,使用 Element - UI 组件库来构建用户界面是非常常见的操作。其中图片上传功能更是在许多项目中频繁出现,比如用户头像上传、商品图片上传等场景。有时候,我们会有这样的需求:当上传图片达到一定数量后…...
高级 SQL 技巧:提升数据处理能力的实用方法
在数据驱动的时代,SQL 作为操作和管理关系型数据库的标准语言,其重要性不言而喻。基础的 SQL 语句能满足日常的数据查询需求,但在处理复杂业务逻辑、进行数据分析和优化数据库性能时,就需要掌握一些高级 SQL 技巧。这些技巧不仅能提高查询效率,还能实现复杂的数据处理任务…...
2.4.5goweb项目上传到csdn的git仓库
在开始使用 Git 之前,你需要先安装它。不同操作系统的安装方法不同: (git先实战,能从仓库上传,下载之后,在听课程,记住大致流程。以后使用就知道往哪里查了) Windows:可以从Git 官方网站下载安…...
Eclipse 插件开发 3 菜单栏
Eclipse 插件开发 3 菜单栏 1 增加菜单2 指定位置3 点击事件4 二级菜单 (静态)5 二级菜单 (动态) 位置locationURI备注菜单栏menu:org.eclipse.ui.main.menu添加到传统菜单工具栏toolbar:org.eclipse.ui.main.toolbar添加到工具栏 1 增加菜单 <?xml version"1.0&quo…...
win11右键菜单改回win10模式
win11右键菜单非常不好用,经常需要点击最下方的“显示更多选项”,下面是win11右键菜单改回win10模式的方法。 按下 Win R 组合键,打开“运行”窗口,输入 cmd,此时不要急着按Enter,按 Ctrl Shift Enter …...
SpringBoot 常用注解通俗解释
SpringBoot 常用注解通俗解释 一、启动类相关 1. SpringBootApplication • 作用:这是SpringBoot项目的"总开关",放在主类上 • 通俗理解:相当于对电脑说:"开机!我要用SpringBoot了!…...
26 Arcgis软件常用工具有哪些
一、画图改图工具(矢量编辑) 挪位置工具(移动工具) 干哈的?选中要素(比如地块、道路)直接拖到新位置,或者用坐标X/Y偏移批量移动,适合“整体搬家”。 磁…...
OpenCV --- 图像预处理(七)
OpenCV — 图像预处理(七) 文章目录 OpenCV --- 图像预处理(七)十七,图像轮廓特征查找17.1 外接矩形17.2 最小外接矩形17.3 最小外接圆 十七,图像轮廓特征查找 图像轮廓特征查找其实就是他的外接轮廓。应用…...
【计算机网络】信息时代的数字神经系统
目录 前言技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解核心作用讲解关键技术模块说明技术选型对比 二、实战演示环境配置要求核心代码实现案例1:Python TCP服务器案例2:网络带宽测试 运行结果验证 三、性能对比测试…...
Adriuno:编程语言基础
Adriuno主要的编程语言是C语言,使得使用者不需要掌握特殊的编程语言,变得更加容易上手。 一、函数 Arduino提供了许多函数,其功能是控制 Arduino开发板,进行数值计算等,包括数字I/O函数、模拟I/O函数、高级I/O函数、时…...
二叉搜索树的实现与应用场景
本章目标 1.二叉搜索树的概念 2.二叉搜索树的性能分析 3.二叉搜索树的实现 4.二叉搜索树的key/key-value的实现场景 1.二叉搜索树的概念 二叉搜索树又叫二叉排序树,它是具有以下性质的树 1.它的左子树不为空,并且左子树上的值都小于根节点 2.它的右子树不为空,并且右子树上的…...
单例模式介绍
单例模式大家都很清楚,最常见的是饿汉式与懒汉式。也有不常见的静态内部类式与枚举式以及,懒汉式的线程安全版本。 单例模式常被用于全局式的配置管理(数据库连接池,日志管理器),资源共享(线程池…...
Pycharm 代理配置
Pycharm 代理配置 文章目录 Pycharm 代理配置1. 设置系统代理1.1 作用范围1.2 使用场景1.3 设置步骤 2. 设置 python 运行/调试代理2.1 作用范围2.2 使用场景2.3 设置步骤 Pycharm 工具作为一款强大的 IDE,其代理配置在实际开发中也是必不可少的,下面介绍…...
springboot入门-repository数据访问层JPA和mybatis
在 Spring Boot 中,Repository 接口是数据访问层(DAO)的核心抽象,而 JpaRepository 和 MyBatis 的实现方式有显著不同。以下是详细解释: 1. JPA 的 Repository 接口为什么使用 interface? (1) 基于接口的动…...
代码随想录算法训练营Day31 | 56. 合并区间 738.单调递增的数字
56. 合并区间 问题描述: 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。 解决方式…...
【教学类-102-19】蝴蝶三色图作品1——卡纸蝴蝶(滴颜料按压对称花纹)A4横版最大号22.85CM
背景需求: 前期做了18次实验,基本实现了三色图三线的各种变化效果和16种图纸大小的批量导入 今天开始制作具体可用的学具——黑卡纸蝴蝶(滴颜料按压对撑颜色) 【教学类-102-11】蝴蝶外轮廓01——Python对黑白图片进行PS填充三种颜色+图案描边+图案填充白色+制作1图2图6图…...
Claude系列模型-20250426
文章目录 Claude 3.7 Sonnet - "Our most intelligent model yet"Claude 3.5 Haiku - "Fastest model for daily tasks"Claude 3.5 Sonnet (Oct 2024)Claude 3 Opus总结Claude 3.7 Sonnet - “Our most intelligent model yet” 特点: 这是目前Claude系列…...
ADC单通道采集实验
设置的步骤如下; #include "adc.h"ADC_HandleTypeDef adc_handle {0}; void adc_init(void) {adc_handle.Instance ADC1; //ADC的基地址adc_handle.Init.DataAlign ADC_DATAALIGN_RIGHT; //…...
启动你的RocketMQ之旅(五)-Broker详细——消息传输
前言: 👏作者简介:我是笑霸final。 📝个人主页: 笑霸final的主页2 📕系列专栏:java专栏 📧如果文章知识点有错误的地方,请指正!和大家一起学习,一…...
100个节点的部署,整合Docker、Kubernetes和Jenkins的详细设计
一、架构设计概览 组件角色: Docker:应用容器化封装,确保环境一致性。Kubernetes(K8s):自动化容器编排,管理多节点集群的调度、扩缩容和自愈。Jenkins:CI/CD流水线驱动,实现代码到生产的自动化流程。集群规模: Master节点:3个(高可用,避免单点故障)。Worker节点:…...
神经网络与计算机视觉
2016 年,随着 AlphaGo 在围棋比赛中击败李世石,“人工智能”、“神经网络”、“深度 学习”等字眼便越来越多的出现在大众眼前,智能化好像成为一种不可逆转的趋势,带给大家新奇感的同时也带来了一丝忧惧:在不远的未来,机器是否真的拥有思维和情感?《终结者》中天网大战人…...
openEuler对比CentOS的核心优势分析
openEuler对比CentOS的核心优势分析 在开源操作系统领域,openEuler与CentOS均占据重要地位,但随着CentOS维护策略的调整(如CentOS 8停止维护,转向CentOS Stream),越来越多的用户开始关注国产化替代方案。o…...
高性能电脑系统优化工具Advanced SystemCare PRO v18.3.0.240 解锁永久专业版
软件介绍 IObit Advanced SystemCare,系统清理维护与安全防护软件,大幅提升整体系统性能和安全!一键AI智能模式,全面扫描优化修复系统,拥有性能加速模式、系统优化、网络加速、启动项优化、软件更新、实时监视清理、隐…...
【C语言练习】005. 编写表达式并确定其值
【C语言练习】005. 编写表达式并确定其值 005. 编写表达式并确定其值示例 1:算术表达式计算过程:最终结果:示例 2:关系和逻辑表达式计算过程:最终结果:示例 3:复合赋值和算术表达式计算过程:最终结果:示例 4:位运算表达式计算过程:最终结果:示例 5:综合表达式计算…...
力扣面试150题--合并两个有序链表和随机链表的复制
Day 33 题目描述 思路 常规题目,比较list1和list2节点的值,取出较小值扩展链表,最后其中一个遍历完直接拼接另外一个即可(归并排序) /*** Definition for singly-linked list.* public class ListNode {* int v…...
测试用例的设计
组合原则:多个选项有效数据建议组合使用(正向功能)、单个选项无效数据组合其他选项有效数据使用(逆向功能) 一、针对登录模块设计测试用例: 1.账号:已注册手机号、已注册邮箱、为空、未注册手机号、未注册邮箱 2.密码:注册密码、为空、错误密码 3.验证码:正确、过期、错误 …...
关于TCP三次握手和四次挥手的疑点
参考文章:浅谈TCP三次握手和四次挥手 1、三次握手的作用 (1)确保双方收到对方的初始序列号:客户端发送SYN包,服务器回复SYN-ACK包,客户端再回复ACK包,确保双方都接收到对方的序列号。 …...
逆向|dy|a_bogus|1.0.1.19-fix.01
2025-04-26 请求地址:aHR0cHM6Ly93d3cuZG91eWluLmNvbS91c2VyL01TNHdMakFCQUFBQV96azV6NkoyMG1YeGt0eHBnNkkzRVRKejlyMEs3d2Y2dU9EWlhvd2ttblZWRnB0dlBPMmMwN2J0WFotcVU4V3M 个人主页的视频数据 我们需要逆向这个接口,所以现在需要分析这个请求, 分析这几个数据包可以发现: 只有…...
【软考-架构】13.5、中间件
✨资料&文章更新✨ GitHub地址:https://github.com/tyronczt/system_architect 文章目录 中间件技术典型应用架构 中间件技术 在分布式系统环境中,出于操作系统和应用程序之间的软件。 主要的中间件有五类: 数据库访问中间件࿱…...
【Redis】基础2:作为缓存
文章目录 1. 一些概念2. 主动更新策略/缓存设计模式2.1 cache-aside pattern(lazy loading)2.2 read-through pattern(针对读操作)2.3 write-through pattern2.4 write behind pattern(write back pattern)…...
豆包,Kim,deepseek对比
以下是豆包、Kimi、DeepSeek的对比与应用: 对比 - 核心技术:DeepSeek-R1完全依赖强化学习驱动,跳过监督微调阶段。Kimi k1.5采用“轻量级SFT预热RL优化”的混合策略。 - 多模态支持:Kimi k1.5支持文本与图像的多模态联合推理。De…...
L2-005 集合相似度
L2-005 集合相似度 - 团体程序设计天梯赛-练习集 给定两个整数集合,它们的相似度定义为:Nc/Nt100%。其中Nc是两个集合都有的不相等整数的个数,Nt是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。 …...
33.状态压缩动态规划
一、算法内容 1.简介 若元素数量比较小(不超过 20 20 20)时,想要存储每个元素取或不取的状态时, 可以借助位运算将状态压缩。 需要借助状态压缩过程的动态规划就是状态压缩 DP(很多地方会简称为状压 DP)…...
WSL 中 nvidia-smi: command not found的解决办法
前言 在使用基于 Linux 的 Windows 子系统(WSL)时,当我们执行某些操作后,可能会遇到输入 nvidia-smi 命令却无法被系统识别的情况。 例如,在终端中输入nvidia-smi 后,系统返回提示 -bash: nvidia-smi: co…...
Linux 进程控制
文章目录 1. 进程创建1.1 fork1.2 写时拷贝 2.进程终止2.1 退出码2.2 进程如何返回退出码 3. 进程等待3.1 wait3.1.1 阻塞等待3.1.2 退出码与退出信号 3.2 waitpid 1. 进程创建 1.1 fork 我们可以使用fork函数来创建子进程,创建子进程后,父子进程之间就…...
使用MobaXterm远程登录Ubuntu系统:SSH服务配置教程
一、MobaXterm介绍 MobaXterm官网:https://mobaxterm.mobatek.net/ MobaXterm类似于Xshell,是一个工具箱,功能比Xshell多。 直接去官网下载安装就可以,本文主要介绍开启Ubuntu的ssh服务,并通过MobaXterm实现远程登录…...
直线模组精度测试的标准是什么?
直线模组的精度测试是确保其性能和稳定性的重要环节。那么,大家知道直线模组精度测试的标准是什么吗? 1、定位精度:以最大行程为基准长度,用从基准位置开始实际移动的距离与指令值之间的最大误差的绝对值来表示。一般来说…...
RK3568 Debian调试记录
文章目录 1、环境介绍2、前言3、debian目录结构3.1、脚本调用顺序 4、编译debian4.1、构建debian编译所需的环境4.2、编译debian4.3、打包 5、系统启动6、debian适配6.1、新增板级配置单6.2、USB6.3、Wi-Fi / BT6.4、屏幕旋转6.5、触摸旋转6.6、时钟 7、测试8、总结 1、环境介绍…...
来自 Bisheng 关于微调的内容总结
来自 Bisheng 关于微调的内容总结 0. 引言1. 关于微调的总结 0. 引言 这篇文章的内容(主要是截图)是来自 Bisheng 关于微调的内容总结,内容来源于 B 站Up主七吟覃_BISHENG负责人的视频,感兴趣的可以观看原视频。 1. 关于微调的总…...
Git 工具的安装
目录 Git 工具介绍 Git 工具安装 创建本地仓库 配置本地仓库 Git 版本控制基本原理 本期开始,我们将学习如何使用 Git 工具,实现多版本控制。 Git 工具介绍 要了解 Git 工具我们得先了解版本控制器的概念。 有这样一个场景,如下图所…...
任务管理系统,Java+Vue,含源码与文档,科学规划任务节点,全程督办保障项目落地提效
前言: 在当今快节奏的工作环境中,高效的任务管理是确保项目按时完成、资源合理分配及团队协作顺畅的关键。任务管理系统作为提升工作效率的重要工具,通过数字化手段帮助用户组织、跟踪和完成各类任务。本文将详细阐述任务管理系统的五大核心…...
JavaScript基础知识合集笔记1——数据类型
文章目录 JavaScript中的数据类型基本数据类型引用类型存储区别 JavaScript中的数据类型 基本数据类型和复杂类型 基本数据类型 基础类型包含六种:Number、Bigint、String、Boolean、Undefined、null、symbol Number(特殊值NaN,意为“不是数值”) c…...
2025.04.26-美团春招笔试题-第四题
📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 04. 图像智能降维处理 问题描述 卢小姐是一家图像处理公司的算法工程师,她正在开发一种高效的图像压缩算法。该算法基于奇异值分解(SVD)技术,通过保留图像矩阵中最重要的特征,在…...
测试基础笔记第十三天
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、流程控制语句-判断语句1.判断语句2.逻辑运算符3.elif多重判断4.if的嵌套5.if与逻辑运算符结合1.and2.or3.not 设计测试用例二、流程控制语句-循环语句1.while语…...