当前位置: 首页 > news >正文

【Linux】39.一个基础的HTTP Web服务器

文章目录

  • 1. 实现一个基础的HTTP Web服务器
    • 1.1 功能实现:
    • 1.2 Log.hpp-日志记录器
    • 1.3 HttpServer.hpp-网页服务器
    • 1.4 Socket.hpp-网络通信器
    • 1.5 HttpServer.cc-服务器启动器


1. 实现一个基础的HTTP Web服务器

1.1 功能实现:

  1. 总体功能

    • 提供Web服务,响应客户端(浏览器)的HTTP请求

    • 支持静态文件服务(如HTML、图片等)

    • 多线程处理并发请求

    • 带日志记录功能

  1. 具体工作流程
浏览器 → 发送HTTP请求 → 服务器↓解析请求↓查找文件↓返回响应↓
浏览器 ← 显示页面 ← 服务器
  1. 各模块职责:

日志记录器(Log.hpp)

  • 记录服务器运行状态
  • 错误追踪和调试

网页服务器(HttpServer.hpp)

  • 解析HTTP请求
  • 处理静态文件
  • 生成HTTP响应
  • 多线程处理请求

网络通信器(Socket.hpp)

  • 处理底层网络通信
  • 管理TCP连接

服务器启动器(HttpServer.cc)

  • 程序入口
  • 初始化和启动服务

1.2 Log.hpp-日志记录器

Log.hpp

#pragma once  // 防止头文件重复包含// 系统头文件包含
#include <iostream>     // 标准输入输出
#include <time.h>       // 时间相关函数
#include <stdarg.h>     // 可变参数处理
#include <sys/types.h>  // 基本系统数据类型
#include <sys/stat.h>   // 文件状态
#include <fcntl.h>      // 文件控制选项
#include <unistd.h>     // UNIX标准函数
#include <stdlib.h>     // 标准库函数// 基础配置宏定义
#define SIZE 1024      // 缓冲区大小
#define LogFile "log.txt"  // 默认日志文件名// 日志级别定义(按严重程度递增)
#define Info 0      // 普通信息:记录系统正常操作信息
#define Debug 1     // 调试信息:记录调试相关信息
#define Warning 2   // 警告信息:记录潜在问题
#define Error 3     // 错误信息:记录错误但不影响系统运行
#define Fatal 4     // 致命错误:记录导致系统崩溃的错误// 日志输出方式定义
#define Screen 1     // 输出到屏幕:直接显示在终端
#define Onefile 2    // 输出到单个文件:所有日志记录到同一个文件
#define Classfile 3  // 分类输出:根据日志级别输出到不同文件class Log {
private:int printMethod;      // 日志输出方式std::string path;     // 日志文件存储路径public:// 构造函数:初始化日志系统Log() {printMethod = Screen;  // 默认输出到屏幕path = "./log/";       // 默认日志目录}// 设置日志输出方式void Enable(int method) {printMethod = method;}// 将日志级别转换为对应的字符串std::string levelToString(int level) {switch (level) {case Info:    return "Info";case Debug:   return "Debug";case Warning: return "Warning";case Error:   return "Error";case Fatal:   return "Fatal";default:      return "None";}}// 根据设置的输出方式打印日志void printLog(int level, const std::string &logtxt) {switch (printMethod) {case Screen:    // 输出到屏幕std::cout << logtxt << std::endl;break;case Onefile:   // 输出到单个文件printOneFile(LogFile, logtxt);break;case Classfile: // 根据日志级别输出到不同文件printClassFile(level, logtxt);break;}}// 将日志输出到指定文件void printOneFile(const std::string &logname, const std::string &logtxt) {std::string _logname = path + logname;// 以追加方式打开文件,如果不存在则创建int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);if (fd < 0) return;  // 打开失败则直接返回write(fd, logtxt.c_str(), logtxt.size());  // 写入日志内容close(fd);  // 关闭文件描述符}// 根据日志级别将日志输出到不同文件void printClassFile(int level, const std::string &logtxt) {std::string filename = LogFile;filename += ".";filename += levelToString(level);  // 构造文件名,如"log.txt.Debug"printOneFile(filename, logtxt);}// 重载函数调用运算符,实现日志记录的核心功能void operator()(int level, const char *format, ...) {// 1. 获取当前时间time_t t = time(nullptr);struct tm *ctime = localtime(&t);// 2. 格式化日志头部(时间和级别信息)char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);// 3. 处理可变参数,格式化日志内容va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 4. 组合完整的日志消息char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);// 5. 输出日志printLog(level, logtxt);}
};// 创建全局日志对象,方便在程序各处使用
Log lg;/* 示例用法:
int main() {lg.Enable(Screen);  // 设置输出到屏幕lg(Info, "Server started on port %d", 8080);lg(Error, "Failed to connect to %s", "database");return 0;
}
*/

1.3 HttpServer.hpp-网页服务器

HttpServer.hpp

功能:

  • HTTP请求处理
  • 多线程服务
  • 静态文件响应
  • Cookie支持
  • 错误页面处理
#pragma once  // 防止头文件重复包含// 基础库和系统库引入
#include <iostream>     // 标准输入输出
#include <string>       // 字符串处理
#include <pthread.h>    // POSIX线程库
#include <fstream>      // 文件流操作
#include <vector>       // 动态数组
#include <sstream>      // 字符串流
#include <sys/types.h>  // 基本系统数据类型
#include <sys/socket.h> // Socket通信
#include <unordered_map> // 哈希表// 自定义头文件
#include "Socket.hpp"   // Socket封装类
#include "Log.hpp"      // 日志系统// 全局常量定义
const std::string wwwroot="./wwwroot"; // web服务器根目录
const std::string sep = "\r\n";        // HTTP消息分隔符
const std::string homepage = "index.html"; // 默认主页static const int defaultport = 8082;    // 默认端口号class HttpServer;  // 前向声明// 线程数据结构:存储每个线程处理的连接信息
class ThreadData
{
public:ThreadData(int fd, HttpServer *s) : sockfd(fd), svr(s) {}public:int sockfd;         // 客户端连接的socket描述符HttpServer *svr;    // HTTP服务器对象指针
};// HTTP请求解析类
class HttpRequest
{
public:// 反序列化HTTP请求void Deserialize(std::string req) {while(true){std::size_t pos = req.find(sep);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+sep.size());  // 移除已处理部分}text = req;  // 保存请求体}// 解析HTTP请求,处理URL和文件路径void Parse(){// 解析请求行(方法、URL、HTTP版本)std::stringstream ss(req_header[0]);ss >> method >> url >> http_version;// 构建文件路径file_path = wwwroot;  if(url == "/" || url == "/index.html") {file_path += "/";file_path += homepage;  // 处理默认主页}else file_path += url;     // 其他页面// 获取文件后缀auto pos = file_path.rfind(".");if(pos == std::string::npos) suffix = ".html";else suffix = file_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 << "file_path: " << file_path << std::endl;std::cout << text << std::endl;}public:std::vector<std::string> req_header;  // 请求头部std::string text;                     // 请求正文// 解析后的请求信息std::string method;       // 请求方法(GET、POST等)std::string url;         // 请求URLstd::string http_version; // HTTP协议版本std::string file_path;   // 请求文件路径std::string suffix;      // 文件后缀
};// HTTP服务器类
class HttpServer
{
public:// 构造函数:初始化端口和支持的内容类型HttpServer(uint16_t port = defaultport) : port_(port){content_type.insert({".html", "text/html"});content_type.insert({".png", "image/png"});}// 启动服务器bool Start(){// 初始化Socket// 1. 创建Socketlistensock_.Socket();/* 这一步完成以下操作:a) 调用系统函数 socket(AF_INET, SOCK_STREAM, 0) 创建TCP Socket- AF_INET: 使用IPv4协议族- SOCK_STREAM: 使用TCP协议- 0: 使用默认协议b) 设置Socket选项- SO_REUSEADDR: 允许地址重用,避免服务器重启时的"地址已被使用"错误*/// 2. 绑定端口listensock_.Bind(port_);/* 这一步完成以下操作:a) 创建sockaddr_in结构体,设置:- sin_family = AF_INET (IPv4)- sin_port = htons(port_) (设置端口号,转换为网络字节序)- sin_addr.s_addr = INADDR_ANY (监听所有网卡接口)b) 调用bind()函数将Socket与地址绑定- 如果端口已被占用或权限不足,会失败*/// 3. 开始监听listensock_.Listen();/* 这一步完成以下操作:a) 调用listen()函数,将Socket转换为监听状态- backlog参数设置为10,表示等待连接队列的最大长度- 超过此长度的新连接请求会被拒绝b) 此后Socket就能接受客户端连接请求- 服务器调用Accept()接受新的连接*/// 主循环:接受并处理连接for (;;){// 准备变量存储客户端信息std::string clientip;    // 将存储客户端的IP地址uint16_t clientport;     // 将存储客户端的端口号// 接受新的客户端连接int sockfd = listensock_.Accept(&clientip, &clientport);/* Accept函数做了这些事:1. 等待客户端连接2. 获取客户端的IP和端口3. 返回新的socket描述符用于与该客户端通信*/// 连接失败则继续等待下一个连接if (sockfd < 0) continue;// 记录新连接日志lg(Info, "get a new connect, sockfd: %d", sockfd);// 创建新线程处理请求// 1. 声明线程ID变量pthread_t tid;    // 用于存储新创建线程的ID// 2. 创建线程数据结构,传入连接描述符和当前服务器对象ThreadData *td = new ThreadData(sockfd, this);/* ThreadData包含:- sockfd:与客户端通信的socket描述符- this:当前服务器对象的指针,用于访问服务器的方法*/// 3. 创建新线程处理请求pthread_create(&tid, nullptr, ThreadRun, td);/* 参数含义:- &tid:存储新线程ID- nullptr:使用默认线程属性- ThreadRun:线程将执行的函数- td:传递给线程函数的参数*/// 新线程会执行ThreadRun函数处理客户端请求// 主线程继续循环等待新的连接}}// 读取HTML文件内容static std::string ReadHtmlContent(const std::string &htmlpath){// 1. 打开文件std::ifstream in(htmlpath, std::ios::binary);/* 说明:- binary模式打开确保文件按原样读取- 不会对换行符进行转换*/// 文件打开失败则返回空字符串if(!in.is_open()) return "";// 2. 获取文件大小in.seekg(0, std::ios_base::end);   // 将读指针移到文件末尾auto len = in.tellg();             // 获取当前位置(即文件大小)in.seekg(0, std::ios_base::beg);   // 将读指针移回文件开头// 3. 读取文件内容std::string content;           // 用于存储文件内容content.resize(len);           // 预分配空间// 一次性读取整个文件内容到字符串中in.read((char*)content.c_str(), content.size());// 4. 关闭文件in.close();return content;  // 返回文件内容}// 根据文件后缀获取Content-Typestd::string SuffixToDesc(const std::string &suffix){// 在content_type映射表中查找文件后缀对应的MIME类型auto iter = content_type.find(suffix);// 如果找不到对应的MIME类型if(iter == content_type.end()) return content_type[".html"];  // 默认返回html的MIME类型:"text/html"else return content_type[suffix];   // 返回找到的MIME类型/* 例如:- .html -> "text/html"- .png  -> "image/png"这个MIME类型会被用在HTTP响应头的Content-Type字段中*/}// 处理HTTP请求void HandlerHttp(int sockfd){// 1. 接收HTTP请求char buffer[10240];ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);/* 参数解释:1. sockfd: 套接字描述符,用于标识与客户端的连接2. buffer: 接收数据的缓冲区3. sizeof(buffer) - 1: 最大接收长度,预留1个字节给'\0'4. 0: 标志位,使用默认行为返回值n:- 大于0:实际接收的字节数- 等于0:连接已关闭- 小于0:接收错误*/if (n > 0){buffer[n] = 0;  // 字符串结束符// 2. 解析HTTP请求HttpRequest req;req.Deserialize(buffer);   // 反序列化请求内容req.Parse();               // 解析请求(获取方法、URL、版本等)// 3. 读取请求的文件内容std::string text;bool ok = true;text = ReadHtmlContent(req.file_path);  // 读取请求的文件if(text.empty())  // 文件不存在或读取失败{ok = false;// 返回错误页面std::string err_html = wwwroot + "/err.html";text = ReadHtmlContent(err_html);}// 4. 构建HTTP响应// 4.1 响应行std::string response_line;if(ok)response_line = "HTTP/1.0 200 OK\r\n";elseresponse_line = "HTTP/1.0 404 Not Found\r\n";// 4.2 响应头std::string response_header = "Content-Length: ";response_header += std::to_string(text.size());response_header += "\r\n";response_header += "Content-Type: ";response_header += SuffixToDesc(req.suffix);  // 设置正确的MIME类型response_header += "\r\n";response_header += "Set-Cookie: name=haha&&passwd=12345";  // 设置Cookieresponse_header += "\r\n";// 4.3 空行std::string blank_line = "\r\n";// 4.4 组装完整响应(响应行+响应头+空行+响应体)std::string response = response_line + response_header + blank_line + text;// 5. 发送响应给客户端send(sockfd, response.c_str(), response.size(), 0);}// 6. 关闭连接close(sockfd);}// 线程运行函数static void *ThreadRun(void *args){pthread_detach(pthread_self());  // 设置线程分离ThreadData *td = static_cast<ThreadData *>(args);td->svr->HandlerHttp(td->sockfd);delete td;return nullptr;}~HttpServer() {}private:Sock listensock_;    // 监听socketuint16_t port_;      // 服务器端口std::unordered_map<std::string, std::string> content_type;  // 支持的内容类型映射
};

1.4 Socket.hpp-网络通信器

Socket.hpp

功能:

  • TCP连接封装
  • 地址绑定
  • 端口监听
  • 客户端连接处理
  • 错误处理
#pragma once  // 防止头文件重复包含// 系统相关头文件
#include <iostream>     // 标准输入输出
#include <string>       // 字符串处理
#include <unistd.h>    // UNIX标准函数定义
#include <cstring>     // C字符串处理
#include <sys/types.h> // 基本系统数据类型
#include <sys/stat.h>  // 文件状态
#include <sys/socket.h> // Socket接口
#include <arpa/inet.h> // IP地址转换函数
#include <netinet/in.h> // IP协议家族
#include "Log.hpp"     // 日志系统// 错误枚举定义
enum
{SocketErr = 2,  // Socket创建错误BindErr,        // 绑定错误ListenErr,      // 监听错误
};// 监听队列长度
const int backlog = 10;// Socket封装类
class Sock
{
public:Sock() {}~Sock() {}public:// 创建Socketvoid Socket(){// 创建TCP Socketsockfd_ = socket(AF_INET, SOCK_STREAM, 0);if (sockfd_ < 0){// 创建失败,记录错误日志并退出lg(Fatal, "socker error, %s: %d", strerror(errno), errno);exit(SocketErr);}// 设置Socket选项:地址重用int opt = 1;setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));}// 绑定端口void Bind(uint16_t port){// 创建并初始化地址结构struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;           // IPv4local.sin_port = htons(port);         // 端口号local.sin_addr.s_addr = INADDR_ANY;   // 监听所有网卡// 绑定地址和端口if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) < 0){// 绑定失败,记录错误日志并退出lg(Fatal, "bind error, %s: %d", strerror(errno), errno);exit(BindErr);}}// 开始监听void Listen(){// 启动监听if (listen(sockfd_, backlog) < 0){// 监听失败,记录错误日志并退出lg(Fatal, "listen error, %s: %d", strerror(errno), errno);exit(ListenErr);}}// 接受连接int Accept(std::string *clientip, uint16_t *clientport){// 准备接收客户端地址信息struct sockaddr_in peer;socklen_t len = sizeof(peer);// 接受新连接int newfd = accept(sockfd_, (struct sockaddr*)&peer, &len);if(newfd < 0){// 接受连接失败,记录警告日志lg(Warning, "accept error, %s: %d", strerror(errno), errno);return -1;}// 获取客户端IP地址char ipstr[64];inet_ntop(AF_INET, &peer.sin_addr, ipstr, sizeof(ipstr));*clientip = ipstr;// 获取客户端端口号*clientport = ntohs(peer.sin_port);return newfd;  // 返回新连接的文件描述符}// 连接服务器(客户端使用)bool Connect(const std::string &ip, const uint16_t &port){// 准备服务器地址信息struct sockaddr_in peer;memset(&peer, 0, sizeof(peer));peer.sin_family = AF_INET;peer.sin_port = htons(port);inet_pton(AF_INET, ip.c_str(), &(peer.sin_addr));// 建立连接int n = connect(sockfd_, (struct sockaddr*)&peer, sizeof(peer));if(n == -1) {// 连接失败std::cerr << "connect to " << ip << ":" << port << " error" << std::endl;return false;}return true;  // 连接成功}// 关闭Socketvoid Close(){close(sockfd_);}// 获取Socket文件描述符int Fd(){return sockfd_;}private:int sockfd_;  // Socket文件描述符
};

1.5 HttpServer.cc-服务器启动器

HttpServer.cc

功能:

  • 程序入口
  • 参数解析
  • 服务器初始化
  • 智能指针管理
// 包含必要的头文件
#include "HttpServer.hpp"  // HTTP服务器类定义
#include <iostream>        // 标准输入输出
#include <memory>         // 智能指针
#include <pthread.h>      // POSIX线程库
#include "Log.hpp"        // 日志系统using namespace std;int main(int argc, char *argv[])
{// 检查命令行参数if(argc != 2)  // 要求必须提供端口号参数{exit(1);   // 参数错误,退出程序}// 将命令行参数转换为端口号uint16_t port = std::stoi(argv[1]);  // 字符串转换为整数// 创建HTTP服务器实例// 以下是三种方式,注释掉的是不推荐的方式// 方式1(不推荐):普通指针,需要手动管理内存// HttpServer *svr = new HttpServer();// 方式2(语法错误):unique_ptr的错误声明方式// std::unique<HttpServer> svr(new HttpServer());// 方式3(推荐):使用智能指针unique_ptr,自动管理内存std::unique_ptr<HttpServer> svr(new HttpServer(port));// 启动服务器svr->Start();  // 开始监听和处理请求// 程序正常退出return 0;
}

相关文章:

【Linux】39.一个基础的HTTP Web服务器

文章目录 1. 实现一个基础的HTTP Web服务器1.1 功能实现&#xff1a;1.2 Log.hpp-日志记录器1.3 HttpServer.hpp-网页服务器1.4 Socket.hpp-网络通信器1.5 HttpServer.cc-服务器启动器 1. 实现一个基础的HTTP Web服务器 1.1 功能实现&#xff1a; 总体功能&#xff1a; 提供We…...

蓝桥杯-小明的背包(动态规划-Java)

0/1背包问题介绍 0/1背包问题是经典的动态规划问题&#xff0c;具体描述如下&#xff1a; 解题思路&#xff1a; 输入数据 首先&#xff0c;程序通过 Scanner 从输入中读取数据&#xff1a; n 表示物品的数量。 v 表示背包的最大容量。 接着读取每个物品的重量和价值&#xff…...

(四十一)Dart 中的空安全与 `late` 关键字教程

Dart 中的空安全与 late 关键字教程 空安全简介 空安全&#xff08;Null Safety&#xff09;是 Dart 语言的一项重要特性&#xff0c;旨在帮助开发者避免空指针异常&#xff08;NullPointerException&#xff09;。空安全通过在编译时检查变量是否可能为 null&#xff0c;从而…...

GaussDB使用指南

目录 1. GaussDB 概述 1.1 GaussDB 简介 1.2 核心技术架构 1.3 适用场景与行业案例 2. GaussDB 安装与部署 2.1 环境准备与依赖检查 2.2 单机版安装&#xff08;Linux&#xff09; 2.3 分布式集群部署 3. GaussDB 基础操作与语法 3.1 数据库连接与用户管理 3.2 DDL …...

算法训练之动态规划(一)

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...

dubbo配置中心

配置中心 简介 配置中心&#xff08;config-center&#xff09;在dubbo中可承担两类职责&#xff1a; 外部化配置&#xff1a;启动配置的集中式存储。流量治理规则存储。 Dubbo动态配置中心定义了两个不同层次的隔离选项&#xff0c;分别是namespace和group。 namespace&a…...

移动端六大语言速记:第11部分 - 内存管理

移动端六大语言速记&#xff1a;第11部分 - 内存管理 本文将对比Java、Kotlin、Flutter(Dart)、Python、ArkTS和Swift这六种移动端开发语言在内存管理方面的特性&#xff0c;帮助开发者理解和掌握各语言的内存管理机制。 11. 内存管理 11.1 垃圾回收机制对比 各语言垃圾回收…...

对象的创建方式有哪些?在虚拟机中具体的创建过程是怎样的?

在Java中&#xff0c;对象的创建方式及其在虚拟机中的具体过程如下&#xff1a; 一、对象的创建方式 使用 new 关键字 最常见的对象创建方式&#xff0c;直接调用类的构造方法。 MyClass obj new MyClass();反射&#xff08;Reflection&#xff09; 通过 Class 或 Constructor…...

openwrt软路由配置3

1.启用sftp文件连接 使用ssh连接openwrt时&#xff0c;我发现无法打开sftp windows进行上传和下载文件&#xff0c;提示 sftp channel closed by server: stderr:ash /usr/libexec/sftp-server:not found 原因是系统刚刚装好后&#xff0c;没有安装openssh-sftp-server包 opk…...

C语言for循环嵌套if相关题目

一、题目引入 以下代码程序运行结果是多少? 二、思路解析 进入一个for循环 a<100 进入第一个if b1不大于20为假 进入第二个if b4 a这时a自增为2 当b4时,满足第二个if条件 1.b4,a2 当b7时,满足第二个if条件 2.bb37,a3 当b10时,满足第二个if条件 …...

Redis与Mysql双写一致性如何保证?

我们在面试的时候redis与mysql双写一致性是一个常考的问题&#xff0c;今天我们就一起探讨一下吧 所谓的一致性就是数据的一致性&#xff0c;在分布式系统中&#xff0c;可以理解为多个节点中数据的值是一致的。 强一致性&#xff1a; 这种一致性级别是最符合用户直觉的&…...

STM32 CRC校验与芯片ID应用全解析:从原理到实践 | 零基础入门STM32第九十七步

主题内容教学目的/扩展视频CRC与芯片ID原理实现CRC校验和读取芯片ID为单片机应用提供数据验证和身份识别的功能。 师从洋桃电子&#xff0c;杜洋老师 &#x1f4d1;文章目录 一、CRC校验功能解析1.1 CRC基本原理1.2 核心功能对比 二、CRC校验应用实战2.1 典型应用场景2.2 程序实…...

《微服务与事件驱动架构》读书分享

《微服务与事件驱动架构》读书分享 Building Event-Driver Microservices 英文原版由 OReilly Media, Inc. 出版&#xff0c;2020 作者&#xff1a;[加] 亚当 • 贝勒马尔 译者&#xff1a;温正东 作者简介&#xff1a; 这本书由亚当贝勒马尔&#xff08;Adam Bellemare…...

⼤模型(LLMs)基础

⼤模型&#xff08;LLMs&#xff09;基础 ⽬前 主流的开源模型体系 有哪些&#xff1f;prefix Decoder 和 causal Decoder 和 Encoder-Decoder 区别是什么&#xff1f;⼤模型LLM的 训练⽬标 是什么&#xff1f;涌现能⼒是啥原因&#xff1f;为何现在的⼤模型⼤部分是Decoder o…...

IDEA :物联网ThingsBoard-gateway配置,运行Python版本,连接thingsboard,接入 MQTT 设备

准备阶段&#xff08;教程只针对本地操作&#xff0c;未涉及虚拟机环境&#xff09; Thingsboard源码编译并运行 没有操作过的小伙伴&#xff0c;可以看我上一篇文章 物联网ThingsBoard源码本地编译篇&#xff0c;超详细教程&#xff0c;小白看过来&#xff01;_thingsboard…...

面向大模型的开发框架LangChain

这篇文章会带给你 如何使用 LangChain&#xff1a;一套在大模型能力上封装的工具框架如何用几行代码实现一个复杂的 AI 应用面向大模型的流程开发的过程抽象 文章目录 这篇文章会带给你写在前面LangChain 的核心组件文档&#xff08;以 Python 版为例&#xff09;模型 I/O 封装…...

每日算法:洛谷U535992 J-C 小梦的宝石收集(双指针、二分)

题目描述 小梦有 n 颗能量宝石&#xff0c;其中第 i 颗的能量为 ai​&#xff0c;但这些能量宝石十分不稳定&#xff0c;随时有可能发生崩坏&#xff0c;导致他们全部消失&#xff01; 小梦想要留住宝石们&#xff0c;不希望他们发生崩坏&#xff0c;同时他发现&#xff1a;如…...

写给新人的深度学习扫盲贴:ReLu和梯度

一、ReLU&#xff08;Rectified Linear Unit&#xff0c;修正线性单元&#xff09; 梯度是深度学习中最常用的激活函数之一&#xff0c;因其简单、高效且能有效缓解梯度消失问题而被广泛使用。 1. 数学定义 函数表达式&#xff1a; $$ \text{ReLU}(x) \max(0, x) \begin{…...

Spring 框架的核心基础:IoC 和 AOP

一、IoC&#xff08;Inversion of Control&#xff0c;控制反转&#xff09; 定义&#xff1a; IoC&#xff08;Inversion of Control&#xff0c;控制反转&#xff09;&#xff0c;就是把对象创建和依赖关系的管理交给 Spring 容器&#xff0c;而不是由程序员手动去创建对象…...

JavaScript逆向工程实战:如何精准定位加密参数生成位置

前言&#xff1a;一个令人困惑的调试案例 最近在进行某网站的JavaScript逆向分析时&#xff0c;我遇到了一个有趣的现象&#xff1a;当我尝试定位一个名为m的加密参数&#xff08;值为MTIwMTE3NDQxODk1NTY1NjkA这样的Base64字符串&#xff09;时&#xff0c;调试器却带我来到了…...

SSM智能停车场管理系统

&#x1f345;点赞收藏关注 → 添加文档最下方联系方式咨询本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345; 项目视频 SS…...

[定位器]晶艺LA1823,4.5V~100V, 3.5A,替换MP9487,MP9486A,启烨科技

Features  4.5V to 100V Wide Input Range  3.5A Typical Peak Current Limit  Integrated 500mΩ low resistance high side power MOS.  Constant On Time Control with Constant Switching Frequency.  180μA Low Quiescent Current  150kHz/240kHz/420kHz Swi…...

天元证券|A股大反攻!北证50涨超10%!芯片股大爆发

今日&#xff0c;A股全线走强。 科技成长股领涨&#xff0c;北证50指数飙升逾10%&#xff0c;科创50也大涨超4%&#xff0c;深证成指、上证指数午后也稳步拉升涨逾1%。值得注意的是&#xff0c;上证50指数临近收盘集合竞价的时候直线拉升。近4600只个股上涨&#xff0c;成交稳步…...

利用python从零实现Byte Pair Encoding(BPE):NLP 中的“变形金刚”

BPE&#xff1a;NLP 界的“变形金刚”&#xff0c;从零开始的奇幻之旅 在自然语言处理&#xff08;NLP&#xff09;的世界里&#xff0c;有一个古老而神秘的传说&#xff0c;讲述着一种强大的魔法——Byte Pair Encoding&#xff08;BPE&#xff09;。它能够将普通的文本“变形…...

最新Web系统全面测试指南

你有没有遇到过这样的情况&#xff1a; 系统上线当天&#xff0c;用户频频报错&#xff0c;运维一脸懵逼&#xff0c;开发说“我本地没问题”&#xff1f; 你明明写了几十个测试用例&#xff0c;结果却还是有 Bug 漏网&#xff1f; Web 系统测试&#xff0c;不只是点点点&#…...

OpenBMC:BmcWeb 处理http请求6 调用路由处理函数

OpenBMC:BmcWeb 处理http请求5 检查权限-CSDN博客 检查完权限后,调用了rule.handle(*req, asyncResp, params); template <typename... Args> class TaggedRule :public BaseRule,public RuleParameterTraits<TaggedRule<Args...>> {void handle(const Req…...

售货机管理系统:智慧零售时代的运营新引擎

一、引言 在快节奏的都市生活中,自动售货机已成为便捷消费的重要场景。然而,传统售货机依赖人工补货、手工对账,常面临库存失衡、设备故障发现滞后、数据孤岛等痛点。如何突破效率瓶颈?本文将深入剖析榕壹云售货机管理系统的项目背景、客户定位、技术与核心功能、系统优势…...

Python基础全解析:从输入输出到字符编码的深度探索

一、Python程序交互的基石&#xff1a;Print函数详解 1.1 基础输出功能 # 输出数字 print(20.5) # 输出浮点数&#xff1a;20.5 print(0b0010) # 输出二进制数&#xff1a;10# 输出字符串 print(Hello World!) # 经典输出示例# 表达式计算 print(4 4 * (2-1)…...

Python第八章02:数据可视化Pyecharts包无法使用

PS:本节纯属个人在学习过程中遇到问题、解决问题的经验分享&#xff0c;对学习进度没影响&#xff0c;没有遇到该问题的小伙伴可跳过。 首先&#xff0c;在学习数据图形化过程中&#xff0c;通过命令提示符安装了Pyecharts包&#xff0c;在命令提示符中验证安装成功。 在PyChar…...

【人工智能】如何通过精准提示工程实现完美的珠宝首饰展示

AI艺术创作指南&#xff1a;如何通过精准提示工程实现完美的珠宝首饰展示 引言&#xff1a;认知边界的突破 在AI艺术创作的漫长探索中&#xff0c;许多创作者面临着相似的困扰&#xff1a;当他们看到别人能够通过算法编织出如同文艺复兴时期细腻油画般的奢华珠宝展示图&#…...

Redis学习总结(持续更新)

Redis 目前在学习redis&#xff0c;遇到的一些问题会放在这里&#xff0c;加深自己的印象。 1. Redis缓存相较于传统Session存储的特点 Session的存储方式&#xff1a; 通常&#xff0c;传统的Session是存储在应用服务器的内存中&#xff0c;比如Tomcat的Session管理器。用户…...

RabbitMQ从入门到实战-3(高可靠性)

文章目录 发送者可靠性发送者重连发送者确认&#xff08;一般不会开启&#xff09;指定returncallback和confrimfallbacktips MQ可靠性数据持久化LazyQueue&#xff08;默认模式且不可更改&#xff09; 消费者的可靠性消费者确认机制消费者失败重试业务幂等性唯一消息id业务判断…...

RTK 实时动态定位概述

01 引言 RTK(实时动态定位,Real-Time Kinematic)是一种高精度的卫星导航定位技术,通过差分校正方法,将GNSS(全球导航卫星系统)的定位精度从米级提升至厘米级(通常1-3厘米),广泛应用于测绘、无人机、自动驾驶、精准农业等领域。 02 概述 1. RTK的基本原理 RTK的核…...

Conda 环境离线迁移实战:解决生产环境网络限制的高效方案20250409

Conda 环境离线迁移实战&#xff1a;解决生产环境网络限制的高效方案 在生产环境无法联网的前提下&#xff0c;如何高效、安全地部署 Python 虚拟环境&#xff0c;是许多企业在实际运维中必须面对的问题。特别是当前常见的开发环境基于 Miniconda&#xff0c;生产环境使用 Ana…...

dify使用知识库

注意 要用向量模型 导入文件 选择向量模型 要下载好后&#xff0c;才可以导入模型&#xff0c; 这个模型没法在ollama中run 聊天工具添加知识库 效果...

HTTP:一.概述

http是干嘛的? 超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由统…...

Appium工作原理及环境的搭建(1)

1、Appium的介绍&#xff1a; 一、什么是Appium Desktop&#xff1f; Appium Desktop是Appium项目的桌面版GUI工具&#xff0c;提供了一个友好的界面&#xff0c;用于启动Appium服务器、查看设备日志、与设备交互、调试自动化脚本等。相比于命令行工具&#xff0c;Appium Des…...

Interactron: Embodied Adaptive Object Detection(训练时进行更新参数) 还没看懂

Interactron: Embodied Adaptive Object Detection 创新点 这些方法通常存在两个主要的共同假设。第一&#xff0c;模型在固定的训练集上进行训练&#xff0c;并在预先录制的测试集上进行评估。第二&#xff0c;模型在训练阶段结束后保持冻结状态&#xff0c;即训练完成后不再…...

【Pandas】pandas DataFrame copy

Pandas2.2 DataFrame Conversion 方法描述DataFrame.astype(dtype[, copy, errors])用于将 DataFrame 中的数据转换为指定的数据类型DataFrame.convert_dtypes([infer_objects, …])用于将 DataFrame 中的数据类型转换为更合适的类型DataFrame.infer_objects([copy])用于尝试…...

Redis基础指令(Windows)

1.cmd命令行启动redis 直接cmd打开整个文件 1.1.启动server 输入指令&#xff1a; redis-server.exe redis.windows.conf 会进入serve端 1.2.启动客户端 &#xff01;&#xff01;重新打开一个cmd&#xff0c;方法和上面一样&#xff01;&#xff01; 之后输入 redis-…...

MV-DLS600P激光振镜立体相机(MV-DLS600P)重要参数解析

功能特性 采用激光振镜技术&#xff0c;亚毫米级图像采集精度 高能效激光模块配合精准曝光同步&#xff0c;性能更稳定 支持多帧融合&#xff0c;无惧金属工件表面反光干扰 支持RGB、深度图同步对齐输出&#xff0c;便于二次开发 配备窄带滤光片&#xff0c;抗干扰能力更强&…...

C语言【输出字符串中的大写字母】

题目 输出字符串中的大写字母 思路&#xff08;注意事项&#xff09; 纯代码 #include<stdio.h> #include<string.h>int main(){char str[20], ans[20];fgets(str, sizeof(str), stdin);str[strcspn(str, "\n")] \0;for (int i 0, j 0; i < strl…...

UniApp基于xe-upload实现文件上传组件

xe-upload地址&#xff1a;文件选择、文件上传组件&#xff08;图片&#xff0c;视频&#xff0c;文件等&#xff09; - DCloud 插件市场 致敬开发者&#xff01;&#xff01;&#xff01; 感觉好用的话&#xff0c;给xe-upload的作者一个好评 背景&#xff1a;开发中经常会有…...

deque容器

1.定义 也叫双端数组&#xff0c;可以对头部进行插入和删除。 2.与vector区别 3.内部工作原理 他是把整个地址划分成多块小地址&#xff08;缓冲区&#xff09;&#xff0c;然后有一个中控区去记录这些地址&#xff0c;然后访问的时候先通过中控区然后再转到相应的缓冲区&am…...

git 总结遇到的问题

git Push 报错 Push failed send-pack: unexpected disconnect while reading sideband packet Total 2269 (delta 418), reused 0 (delta 0), pack-reused 0 the remote end hung up unexpectedly 解决方案&#xff1a;增加 Git 的缓冲区&#xff0c;有时由于数据量大或网络…...

python基础语法11-文件读写

在 Python 中&#xff0c;文件操作是日常编程中的常见任务之一。Python 提供了简单且强大的工具来读取和写入文件。通过使用内置的 open() 函数、read()、readline()、write() 等方法&#xff0c;我们可以轻松实现对文件的操作。此外&#xff0c;Python 的 with 语句可以帮助我…...

Webstorm 使用搜不到node_modules下的JS内容 TS项目按Ctrl无法跳转到函数实现

将node_modules标记为不排除&#xff0c;此时要把内存改大&#xff0c;不然webstorm中途建立索引时&#xff0c;会因为内存不足&#xff0c;导致索引中途停止&#xff0c;造成后续搜索不出来 更改使用内存设置 内存调为4096 若出现搜不出来js内容时&#xff0c;请直接重启下该项…...

转行嵌入式,需要自学多久?

作为一个本硕都学机械&#xff0c;却阴差阳错进入嵌入式行业的老兵&#xff0c;这个问题我能聊一整天。十几年前我还在工厂车间穿着工装和机床打交道&#xff0c;偶然接触到单片机后就一发不可收拾。 转行这条路我走得异常艰辛&#xff0c;踩过的坑比写过的代码还多。去年我终…...

BLE 协议栈事件驱动机制详解

在 BlueNRG-LP 等 BLE 系统中,事件驱动是控制状态转移、数据交互和外设协作的基础。本文将深入讲解 BLE 协议栈中事件的来源、分发流程、处理结构与实际工程实践策略,帮助你构建稳定、可维护的 BLE 系统。 📦 一、BLE 事件的来源分类 BLE 协议栈中的事件严格来自协议栈本身…...

AI开发学习路线(闯关升级版)

以下是一份轻松版AI开发学习路线&#xff0c;用「闯关升级」的方式帮你从零开始变身AI开发者&#xff0c;每个阶段都配有有趣的任务和实用资源&#xff0c;保证不枯燥、可落地&#xff01;&#x1f447; 目录 &#x1f530; 新手村&#xff1a;打基础&#xff08;1-2个月&…...