ESP32开发入门(七):HTTP开发实践
一、HTTP协议基础
1.1 什么是HTTP?
HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最为广泛的一种网络协议,用于从服务器传输超文本到本地浏览器。它是一种无状态的请求/响应协议,工作在客户端-服务器计算模型中。
1.2 HTTP的工作原理
HTTP协议基于请求-响应模型,主要包含以下组件:
-
客户端(Client):发送HTTP请求(如浏览器、ESP32等设备)
-
服务器(Server):接收请求并返回响应
-
请求方法:GET、POST、PUT、DELETE等
-
状态码:200(成功)、404(未找到)、500(服务器错误)等
ESP32设备(客户端) --HTTP请求--> Web服务器 <--HTTP响应-- 浏览器或其他客户端
1.3 HTTP的核心特性
-
简单快速:基于文本的简单协议
-
无连接:每次连接只处理一个请求
-
无状态:协议不保留之前的请求信息
-
灵活:可以传输任意类型的数据
-
支持多种请求方法:满足不同场景需求
1.4 HTTP在物联网中的应用
-
设备数据上报:向服务器发送传感器数据
-
远程配置:从服务器获取设备配置
-
固件升级:通过HTTP下载固件包
-
Web控制界面:提供设备管理页面
-
API交互:与其他系统集成
二、ESP32-S3 HTTP通信程序 (FreeRTOS + Arduino框架)
下面是一个基于ESP32-S3的HTTP通信程序,使用FreeRTOS和Arduino框架实现。这个程序包含HTTP客户端功能,可以向服务器发送GET和POST请求。
#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
// WiFi配置
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
// 服务器配置
const char* serverUrl = "http://你的服务器地址:端口/api/data"; // 示例:"http://192.168.1.100:3000/api/data"
// FreeRTOS任务句柄
TaskHandle_t httpTaskHandle = NULL;
TaskHandle_t wifiTaskHandle = NULL;
// 连接WiFi函数
void connectToWiFi() {Serial.println();Serial.print("正在连接WiFi: ");Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {vTaskDelay(500 / portTICK_PERIOD_MS);Serial.print(".");}
Serial.println("");Serial.println("WiFi已连接");Serial.print("IP地址: ");Serial.println(WiFi.localIP());
}
// 发送HTTP GET请求
void sendHttpGetRequest() {if (WiFi.status() == WL_CONNECTED) {HTTPClient http;Serial.print("发送GET请求到: ");Serial.println(serverUrl);http.begin(serverUrl);int httpCode = http.GET();if (httpCode > 0) {Serial.printf("HTTP响应码: %d\n", httpCode);if (httpCode == HTTP_CODE_OK) {String payload = http.getString();Serial.println("服务器响应:");Serial.println(payload);}} else {Serial.printf("GET请求失败, 错误: %s\n", http.errorToString(httpCode).c_str());}http.end();} else {Serial.println("WiFi未连接,无法发送请求");}
}
// 发送HTTP POST请求
void sendHttpPostRequest() {if (WiFi.status() == WL_CONNECTED) {HTTPClient http;Serial.print("发送POST请求到: ");Serial.println(serverUrl);http.begin(serverUrl);http.addHeader("Content-Type", "application/json");// 创建JSON格式的POST数据String httpRequestData = "{\"deviceId\":\"ESP32-S3\",\"temperature\":25.5,\"humidity\":60}";int httpCode = http.POST(httpRequestData);if (httpCode > 0) {Serial.printf("HTTP响应码: %d\n", httpCode);if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_CREATED) {String payload = http.getString();Serial.println("服务器响应:");Serial.println(payload);}} else {Serial.printf("POST请求失败, 错误: %s\n", http.errorToString(httpCode).c_str());}http.end();} else {Serial.println("WiFi未连接,无法发送请求");}
}
// HTTP任务函数
void httpTask(void *pvParameters) {while (1) {// 每隔10秒发送一次请求static uint32_t lastRequestTime = 0;uint32_t now = millis();if (now - lastRequestTime > 10000) {lastRequestTime = now;// 交替发送GET和POST请求static bool sendGet = true;if (sendGet) {sendHttpGetRequest();} else {sendHttpPostRequest();}sendGet = !sendGet;}vTaskDelay(100 / portTICK_PERIOD_MS);}
}
// WiFi监控任务函数
void wifiMonitorTask(void *pvParameters) {while (1) {if (WiFi.status() != WL_CONNECTED) {Serial.println("WiFi连接丢失,尝试重新连接...");connectToWiFi();}vTaskDelay(10000 / portTICK_PERIOD_MS); // 每10秒检查一次}
}
void setup() {Serial.begin(115200);// 初始化WiFi连接connectToWiFi();// 创建HTTP任务xTaskCreatePinnedToCore(httpTask, // 任务函数"HTTP Task", // 任务名称8192, // 堆栈大小NULL, // 参数1, // 优先级&httpTaskHandle, // 任务句柄1 // 运行在核心1上);// 创建WiFi监控任务xTaskCreatePinnedToCore(wifiMonitorTask, // 任务函数"WiFi Task", // 任务名称4096, // 堆栈大小NULL, // 参数1, // 优先级&wifiTaskHandle, // 任务句柄0 // 运行在核心0上);
}
void loop() {// 主循环为空,所有功能由FreeRTOS任务处理vTaskDelay(1000 / portTICK_PERIOD_MS);
}
2.1 代码说明
-
WiFi连接:
-
使用
WiFi.begin()
连接到指定的WiFi网络 -
单独的WiFi监控任务持续检查连接状态并在断开时重新连接
-
-
HTTP功能:
-
使用HTTPClient库实现HTTP协议
-
支持GET和POST请求
-
POST请求发送JSON格式数据
-
自动处理HTTP响应
-
-
FreeRTOS集成:
-
创建了两个任务:一个用于HTTP通信,一个用于WiFi监控
-
任务运行在不同的核心上以提高效率
-
使用
vTaskDelay()
代替delay()
以确保不阻塞其他任务
-
-
多任务处理:
-
HTTP任务负责定期发送HTTP请求
-
WiFi任务持续监控网络连接状态
-
2.2 使用说明
-
修改
ssid
和password
为你自己的WiFi配置 -
修改
serverUrl
为你的服务器地址和API端点 -
根据需要调整POST请求的内容和格式
-
请求频率可以在
httpTask
函数中调整
2.3 所需库
-
WiFi.h (Arduino ESP32核心自带)
-
HTTPClient (Arduino ESP32核心自带)
三、HTTP验证步骤 - 搭建Node.js服务器
为了验证ESP32的HTTP功能,我们可以使用Node.js搭建一个简单的服务器,接收ESP32的请求并返回响应。
下面我将详细介绍如何搭建一个完整的Node.js服务器,并将HTML页面数据整合到server.js文件中,以便于ESP32通过HTTP协议与服务器进行通信。
注意:若你电脑没安装node,请自行百度安装,网上教程较多,这里就不赘述了。
3.1 创建Node.js服务器
-
新建一个文件夹作为项目目录
-
在该目录下创建
server.js
文件,内容如下:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
// 中间件
app.use(bodyParser.json());
// 存储接收到的数据
let receivedData = [];
// HTML页面内容
const htmlPage = `
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ESP32 数据监控</title><style>body {font-family: Arial, sans-serif;margin: 20px;}.data-container {margin-top: 20px;padding: 15px;border: 1px solid #ddd;border-radius: 5px;background-color: #f9f9f9;}button {padding: 10px 15px;background-color: #4CAF50;color: white;border: none;border-radius: 4px;cursor: pointer;}button:hover {background-color: #45a049;}.data-item {margin-bottom: 10px;padding: 10px;border-bottom: 1px solid #eee;}.timestamp {color: #666;font-size: 0.9em;}</style>
</head>
<body><h1>ESP32 数据监控</h1><button id="refreshBtn">刷新数据</button><div class="data-container"><h2>最新上报数据 (共<span id="dataCount">0</span>条)</h2><div id="dataDisplay"><p>暂无数据...</p></div></div>
<script>const refreshBtn = document.getElementById('refreshBtn');const dataDisplay = document.getElementById('dataDisplay');const dataCount = document.getElementById('dataCount');// 格式化数据显示function formatData(data) {if (data.receivedData && data.receivedData.length > 0) {return data.receivedData.map(item => \`<div class="data-item"><div><strong>设备ID:</strong> \${item.data.deviceId || '未知'}</div><div><strong>温度:</strong> \${item.data.temperature || 'N/A'}°C</div><div><strong>湿度:</strong> \${item.data.humidity || 'N/A'}%</div><div class="timestamp">\${new Date(item.timestamp).toLocaleString()}</div></div>\`).join('');}return '<p>暂无数据...</p>';}// 获取数据函数async function fetchData() {try {const response = await fetch('/api/data');const data = await response.json();dataCount.textContent = data.receivedData ? data.receivedData.length : 0;dataDisplay.innerHTML = formatData(data);} catch (error) {dataDisplay.innerHTML = \`<p style="color:red;">获取数据失败: \${error.message}</p>\`;}}// 初始加载数据document.addEventListener('DOMContentLoaded', fetchData);// 按钮点击事件refreshBtn.addEventListener('click', fetchData);// 每5秒自动刷新setInterval(fetchData, 5000);</script>
</body>
</html>
`;
// 首页路由 - 返回HTML页面
app.get('/', (req, res) => {res.send(htmlPage);
});
// GET请求处理 - 获取所有数据
app.get('/api/data', (req, res) => {console.log('收到GET请求');res.status(200).json({message: '数据获取成功',receivedData: receivedData,timestamp: new Date().toISOString()});
});
// POST请求处理 - 接收ESP32数据
app.post('/api/data', (req, res) => {console.log('收到POST请求:', req.body);// 验证数据if (!req.body.deviceId) {return res.status(400).json({error: '缺少必要字段: deviceId'});}// 存储数据receivedData.push({data: req.body,timestamp: new Date().toISOString()});// 限制存储的数据量if (receivedData.length > 50) {receivedData = receivedData.slice(-50);}res.status(201).json({message: '数据接收成功',yourData: req.body});
});
// 清空数据接口
app.delete('/api/data', (req, res) => {receivedData = [];res.status(200).json({message: '所有数据已清空'});
});
// 启动服务器
app.listen(port, () => {console.log(`服务器运行在 http://localhost:${port}`);console.log(`API端点:`);console.log(`GET / - 查看数据监控页面`);console.log(`GET /api/data - 获取所有接收到的数据`);console.log(`POST /api/data - 接收ESP32发送的数据`);console.log(`DELETE /api/data - 清空所有数据`);
});
3.1.1 代码详细说明
3.1.1.1 初始化设置
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
-
引入Express框架和body-parser中间件
-
创建Express应用实例
-
设置服务器端口为3000
3.1.1.2 数据存储
let receivedData = [];
-
使用一个数组来存储ESP32发来的所有数据
-
每个数据项包含原始数据和接收时间戳
3.1.1.3 HTML页面整合
const htmlPage = `...`;
-
将完整的HTML页面内容作为模板字符串存储在变量中
-
包含CSS样式和内联JavaScript
-
使用ES6模板字符串语法方便插入变量
3.1.1.4 路由处理
-
首页路由:
app.get('/', (req, res) => {res.send(htmlPage); });
-
处理根路径请求
-
直接返回HTML页面内容
-
-
GET API接口:
app.get('/api/data', (req, res) => {res.json({message: '数据获取成功',receivedData: receivedData,timestamp: new Date().toISOString()}); });
-
返回所有存储的数据
-
包含状态信息和时间戳
-
-
POST API接口:
app.post('/api/data', (req, res) => {// 数据验证和存储res.status(201).json({message: '数据接收成功',yourData: req.body}); });
-
接收ESP32发来的JSON数据
-
验证必要字段
-
存储数据并返回确认
-
-
DELETE API接口:
app.delete('/api/data', (req, res) => {receivedData = [];res.json({ message: '所有数据已清空' }); });
-
清空存储的数据
-
用于测试和调试
-
3.1.1.5 前端JavaScript功能
// 格式化数据显示
function formatData(data) {// 将JSON数据转换为HTML显示
}
// 获取数据函数
async function fetchData() {// 从/api/data获取数据并更新页面
}
// 事件监听和自动刷新
document.addEventListener('DOMContentLoaded', fetchData);
refreshBtn.addEventListener('click', fetchData);
setInterval(fetchData, 5000);
-
使用Fetch API获取数据
-
动态更新页面内容
-
自动刷新和手动刷新功能
-
数据格式化显示
3.2 安装依赖
在项目目录下运行以下命令安装必要的依赖:
npm init -y
npm install express body-parser
3.3 启动服务器
node server.js
服务器启动后,你将在控制台看到:
服务器运行在 http://localhost:3000
现在你可以通过浏览器访问http://localhost:3000
来查看ESP32上报的数据。
3.4 验证步骤
-
确保你的PC和ESP32在同一个局域网
-
修改ESP32代码中的
serverUrl
为你的PC的IP地址和端口(如http://192.168.1.100:3000/api/data
) -
上传ESP32代码并打开串口监视器
-
在浏览器中访问
http://localhost:3000
-
观察串口输出和网页显示的数据
3.6 预期结果
-
串口输出:
发送GET请求到: http://192.168.1.100:3000/api/data HTTP响应码: 200 服务器响应: {"message":"Hello from Node.js server!","receivedData":[...],"timestamp":"..."} 发送POST请求到: http://192.168.1.100:3000/api/data HTTP响应码: 201 服务器响应: {"message":"Data received successfully","yourData":{"deviceId":"ESP32-S3","temperature":25.5,"humidity":60}}
-
网页显示:
最新上报数据 {"message": "Hello from Node.js server!","receivedData": [{"data": {"deviceId": "ESP32-S3","temperature": 25.5,"humidity": 60},"timestamp": "..."}],"timestamp": "..." }
四、实际项目应用示例
4.1 环境监测系统
功能设计:
-
定期上报温湿度数据
-
从服务器获取配置参数
-
实现固件升级检查
void checkForUpdates() {HTTPClient http;http.begin("http://yourserver.com/api/update");int httpCode = http.GET();if (httpCode == HTTP_CODE_OK) {String payload = http.getString();DynamicJsonDocument doc(1024);deserializeJson(doc, payload);if (doc["available"] == true) {String newVersion = doc["version"];String firmwareUrl = doc["url"];if (newVersion != currentFirmwareVersion) {startFirmwareUpdate(firmwareUrl);}}}http.end();
}
4.2 远程控制面板
功能设计:
-
提供Web控制界面
-
实现设备状态实时显示
-
支持多设备管理
void handleRoot() {String html = "<html><body>";html += "<h1>ESP32 Control Panel</h1>";html += "<p>Temperature: " + String(readTemperature()) + "°C</p>";html += "<p>Humidity: " + String(readHumidity()) + "%</p>";html += "<form method='post' action='/control'>";html += "<button name='led' value='on'>Turn LED On</button>";html += "<button name='led' value='off'>Turn LED Off</button>";html += "</form>";html += "</body></html>";server.send(200, "text/html", html);
}
五、HTTP最佳实践与优化
-
安全考虑:
-
使用HTTPS替代HTTP
-
实现API密钥验证
-
限制请求频率
-
-
性能优化:
-
复用HTTPClient对象
-
减少不必要的头信息
-
使用连接池
-
-
错误处理:
-
实现自动重试机制
-
添加超时设置
-
记录错误日志
-
-
数据格式:
-
使用JSON进行数据交换
-
压缩大数据量
-
分页获取大量数据
-
六、常见HTTP服务器选择
-
本地测试:
-
Node.js + Express
-
Python Flask
-
PHP内置服务器
-
-
生产环境:
-
Nginx
-
Apache
-
IIS
-
-
云服务:
-
AWS API Gateway
-
阿里云API网关
-
腾讯云API网关
-
七、总结与扩展
HTTP作为互联网的基础协议,与ESP32的结合为物联网设备提供了简单可靠的数据通信方案,相对于上一篇MQTT协议,HTTP协议的开发和验证更为简单,若你对MQTT开发感兴趣,可查看ESP32开发入门(六):MQTT开发实践。掌握HTTP开发后,您可以进一步:
-
研究HTTPS安全连接
-
学习WebSocket实现实时通信
-
探索RESTful API设计
-
了解gRPC等高效协议
通过本篇教程,您应该已经掌握了ESP32上HTTP开发的核心知识。实际项目中,建议从简单的原型开始,逐步增加功能复杂度,并始终考虑安全性和性能问题。
相关文章:
ESP32开发入门(七):HTTP开发实践
一、HTTP协议基础 1.1 什么是HTTP? HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最为广泛的一种网络协议,用于从服务器传输超文本到本地浏览器。它是一种无状态的请求/响应协议,工作…...
【强化学习】强化学习算法 - 马尔可夫决策过程
马尔可夫决策过程 (Markov Decision Process, MDP) 1. MDP 原理介绍 马尔可夫决策过程 (MDP) 是强化学习 (Reinforcement Learning, RL) 中用于对序贯决策 (Sequential Decision Making) 问题进行数学建模的标准框架。它描述了一个智能体 (Agent) 与环境 (Environment) 交互的…...
数据结构【二叉搜索树(BST)】
二叉搜索树 1. 二叉搜索树的概念2. 二叉搜索树的性能分析3.二叉搜索树的插入4. 二叉搜索树的查找5. 二叉搜索树的删除6.二叉搜索树的实现代码7. 二叉搜索树key和key/value使用场景7.1 key搜索场景:7.2 key/value搜索场景: 1. 二叉搜索树的概念 二叉搜索…...
振动临近失效状态,怎么频谱会是梳子?
这是一个破坏性试验的终末期振动波形。左边时域,右边频域。这是咋回事,时域看起来原本很正常的冲击信号,怎么频域是那个鬼样子。 同一组波形,放大后的频域 - 低频部分: 一个解释:...
橡胶制品行业质检管理的痛点 质检LIMS如何重构橡胶制品质检价值链
橡胶制品广泛应用于汽车、医疗、航空等领域,其性能稳定性直接关联终端产品的安全性。从轮胎耐磨性测试到密封件耐腐蚀性验证,每一项检测数据都是企业参与市场竞争的核心筹码。然而,传统实验室管理模式普遍面临设备调度混乱、检测流程追溯断层…...
【CTFSHOW_Web入门】命令执行
文章目录 命令执行web29web30web31web32web33web34web35web36web37web38web39web40web41web42web43web44web45web46web47web48web49web50web51web52web53web54web55web56web57web58web59web60web61web62web63web64web65web66web67web68web69web70web71web72web73web74web75web7…...
三维底座+智能应用,重构城市治理未来
在“数字中国”战略的引领下,住房和城乡建设领域正迎来一场深刻的数字化转型浪潮。2024年《“数字住建”建设整体布局规划》的发布,明确提出以“CIM”(城市信息模型)为核心,构建城市三维数字底座,推动住建行…...
养生:塑造健康生活的良方
养生是一场贯穿生活的自我关爱行动,从饮食、运动、睡眠到心态调节,每一个环节都对健康有着深远影响。以下为你带来全面且实用的养生策略。 饮食养生:科学搭配,呵护肠胃 合理规划三餐,遵循 “早营养、午均衡、晚清淡”…...
docker 镜像的导出和导入(导出完整镜像和导出容器快照)
一、导出原始镜像 1. 使用 docker save 导出完整镜像 适用场景:保留镜像的所有层、元数据、标签和历史记录,适合迁移或备份完整镜像环境。 操作命令 docker save -o <导出文件名.tar> <镜像名:标签>示例:docker save -o milvu…...
NestJS 框架深度解析
框架功能分析 NestJS 是一个基于 Node.js 的渐进式框架,专为构建高效、可扩展的服务器端应用程序而设计。其核心理念结合了 面向对象编程(OOP)、函数式编程(FP) 和 函数式响应式编程(FRP)&…...
游戏引擎学习第267天:为每个元素添加裁剪矩形
仓库已满:https://gitee.com/mrxiao_com/2d_game_6 新仓库:https://gitee.com/mrxiao_com/2d_game_7 回顾并为今天的内容定下基调 我们今天的主要目标是对游戏的调试“Top List”进行改进,也就是用来显示游戏中耗时最多的函数或模块的性能分析列表。昨天我们已经实…...
基于阿里云DataWorks的物流履约时效离线分析
基于阿里云DataWorks的物流履约时效离线分析2. 数仓模型构建 ORC和Parquet区别: 压缩率与查询性能 压缩率 ORC通常压缩率更高,文件体积更小,适合存储成本敏感的场景。 Parquet因支持更灵活的嵌套结构,压缩率略…...
web 自动化之 selenium 元素四大操作三大切换等待
文章目录 一、元素的四大操作二、三大切换&等待1、切换窗口:当定位的元素不在当前窗口,则需要切换窗口2、切换iframe:当定位的元素在frame/iframe,则需要切换 一、元素的四大操作 1、输入 2、点击 3、获取文本 4、获取属性 import time…...
前端取经路——性能优化:唐僧的九道心经
大家好,我是老十三,一名前端开发工程师。性能优化如同唐僧的九道心经,是前端修行的精髓所在。在本文中,我将为你揭示从网络传输到渲染优化的九大关键技术,涵盖HTTP协议、资源加载策略、缓存控制等核心难题。通过这些实…...
前端工程化和性能优化问题详解
选自己熟悉的内容当作重难点,最好是前端相关的 以下是面向前端面试官介绍前端工程化和性能优化问题的结构化回答框架,结合行业标准和实战经验进行整合: 一、前端工程化核心解析 定义与目标 前端工程化是通过工具链和规范化流程,将…...
【应急响应】- 日志流量如何分析?
【应急响应】- 日志流量如何下手?https://mp.weixin.qq.com/s/dKl8ZLZ0wjuqUezKo4eUSQ...
8b10b编解码仿真
一、基本概念 8B/10B编码(8-bit to 10-bit encoding)是一种将8位数据(包括数据字符和控制字符)转换为10位符号(Symbol)的编码技术,由IBM工程师Al Widmer和Peter Franaszek于1983年提出。其核心思…...
软件工程之面向对象分析深度解析
前文基础: 1.软件工程学概述:软件工程学概述-CSDN博客 2.软件过程深度解析:软件过程深度解析-CSDN博客 3.软件工程之需求分析涉及的图与工具:软件工程之需求分析涉及的图与工具-CSDN博客 4.软件工程之形式化说明技术深度解…...
常见标签语言的对比
XML、JSON 和 YAML 是常见的数据序列化格式 相同点 结构化数据表示 三者均支持嵌套结构,能描述复杂的数据层级关系(如对象、数组、键值对)。跨平台兼容性 均为纯文本格式,可被多种编程语言解析,适用于跨系统数据交换…...
【Linux】环境变量(图文)
目录 一、main函数的参数解释: 1、argc和argc的解释 2、为什么要这样设置? 3、注意: 4、命令行计算器: 二、认识环境变量 三、见见环境变量 1、执行一个程序的前提 2、指令:echo $PATH 3、为什么系统自带的指令…...
基于OpenCV的人脸识别:EigenFaces算法
文章目录 引言一、概述二、代码解析1. 准备工作2. 加载训练图像3. 设置标签4. 准备测试图像5. 创建和训练识别器6. 进行预测7. 显示结果 三、代码要点总结 引言 人脸识别是计算机视觉领域的一个重要应用,今天我将通过一个实际案例来展示如何使用OpenCV中的EigenFac…...
跟我学C++中级篇——STL容器的查找对比
一、C标准库的查找 在C的STL中,对容器或相关序列的查找中,有两种方式,一种是std::find,另外一种是std::search。而且在它们的基础上,还衍生出std::find_if、std::find_if_not、std::find_end等和std::search_n、range…...
解构C++高级命名空间:构建空间作用域·控制兼容
前引:C作为C语言的继承者,也是其掘墓人。在编程语言的演化长河中,C始终游走在【兼容】与【革新】的路上。C程序员眼中(高效直接)的全局函数,对于C开发者来说是【命名空间污染的炸弹】,如果C未发…...
怎么判断是不是公网IP?如何查看自己本地路由器是内网ip还是公网?
在网络世界中,IP 地址如同每台设备的 “门牌号”,起着至关重要的标识作用。而 IP 地址又分为公网 IP 和私网 IP,准确判断一个 IP 属于哪一类,对于网络管理、网络应用开发以及理解网络架构等都有着重要意义。接下来,我们…...
微服务中 本地启动 springboot 无法找到nacos配置 启动报错
1. 此处的环境变量需要匹配nacos中yml配置文件名的后缀 对于粗心的小伙伴在切换【测试】【开发】环境的nacos使用时会因为这里导致项目总是无法启动成功...
android-ndk开发(11): 安装 repo 命令
1. 长话短说 mkdir ~/soft/bin curl -L https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o repo chmod x repo~/.pathrc 添加: export PATH$PATH:~/soft/bin2. 短话长说 repo 的官方介绍页面: https://gerrit.googlesource.com/git-repo/ repo 的官方下载地…...
【设计模式】GoF设计模式之策略模式(Strategy Pattern)
设计模式之策略模式 Strategy Pattern V1.0核心概念角色代码示例程序运行结果代码讲解 适用范围 V1.0 核心概念 策略模式是一种行为型设计模式,其核心思想是业务类执行某个动作时,可以使用该动作的不同的实现,并在程序运行中可以切换使用该…...
QT6(35)4.8定时器QTimer 与QElapsedTimer:理论,例题的界面搭建,与功能的代码实现。
(112) (113)模仿随书老师给的源代码搭建的, LCD 显示的部分不一样 : (114)以下开始代码完善: 关联定时器的信号与槽函数 : (115)…...
用Python监控金价并实现自动提醒!附完整源码
💂 个人网站:【 摸鱼游戏】【神级代码资源网站】【星海网址导航】💻香港大宽带-4H4G 20M只要36/月👉 点此查看详情 在日常投资中,很多朋友喜欢在一些平台买点黄金,低买高卖赚点小差价。但黄金价格实时波动频繁…...
加密领域 AI Agent 的崛起:DeFAI 如何重塑金融
原文:https://polkadot.com/blog/defai-crypto-ai-agents-explained/ 编译:OneBlock 一些创新大肆宣扬,另一些则在后台默默酝酿,不断迭代,直到它们突然无处不在,去中心化的金融系统也不例外。DeFi 解锁了…...
电位器如何接入西门子PLC的模拟量输入
1.设计思考 我现在手上有一个三线10kΩ的滑动变阻器,想让其当作模拟量接入西门子PLC中,外部改变电阻,PLC程序中能看到对应的阻值或电压,这样可以练习模拟量输入这个知识点! 2.了解模拟量的种类 模拟量一般有电压型和…...
发那科机器人5(异常事件和程序备份加载+ROBOGUIDE离线仿真)
发那科机器人5(异常事件和程序备份加载+ROBOGUIDE离线仿真) 一,异常事件和程序备份加载1,常见异常事件2,零点复归介绍3,程序备份-加载(未整理)二,`ROBOGUIDE`离线仿真1,仿真软件简介及安装步骤(未整理)2,机器人==导入与工具==与==工件添加==2.1,机器人导入(未整…...
第二章 如何安装KEIL5和新建工程
单芯片解决方案,开启全新体验——W55MH32 高性能以太网单片机 W55MH32是WIZnet重磅推出的高性能以太网单片机,它为用户带来前所未有的集成化体验。这颗芯片将强大的组件集于一身,具体来说,一颗W55MH32内置高性能Arm Cortex-M3核心…...
【Lattice FPGA 开发】Diamond在线调试Reveal逻辑乱跳的解决
在Vivado中在always块中写逻辑时如果出现always块中的异步复位敏感词在块内部未使用的情况,如下例的rst: always (posedge clk or posedge rst) begin if(~tx_sense_flag)o_rd_adr < d1;else if((o_rd_adr d94) & (bit_cnt d7))o_rd_adr <…...
跨浏览器自动化测试的智能生成方法
一、背景与挑战:跨浏览器测试为什么“难”? 在现代Web应用开发中,跨浏览器兼容性是用户体验的底线保障。面对Chrome、Firefox、Safari、Edge乃至IE、移动浏览器等多种运行环境,开发者与测试人员常面临: 相同DOM在不同…...
docker操作镜像-以mysql为例
Docker安装使用-CSDN博客 docker操作镜像-以mysql为例 当安装一个新的镜像时可以登录https://hub.docker.com/直接搜索想要安装的镜像,查看文档 1)拉取镜像 docker pull mysql 或者 docker pull mysql:版本号 然后直接跳到第4)步即可 2…...
【Yolo精读+实践+魔改系列】Yolov3论文超详细精讲(翻译+笔记)
前言 前面咱们已经把 YOLOv1 和 YOLOv2 的老底都给掀了,今天轮到 YOLOv3 登场,这可是 Joseph Redmon 的“封神之作”。讲真,这哥们本来是搞学术的,结果研究的模型被某些军方拿去“整点活”——不是做人是做武器的那种活。于是他一…...
【Python从入门到精通】--‘@‘符号的作用
在Python中,符号主要有三种用途:装饰器(Decorator)、矩阵乘法运算符(Python 3.5)以及类型提示中的修饰符(如typing)。 目录 1.--装饰器(Decorator) 2.--矩…...
git命令积累(个人学习)
如何将docx文件不上传? 创建或编辑 .gitignore 文件 打开 .gitignore 文件,添加以下内容来忽略所有 .docx 文件: *.docx清除已追踪的 .docx 文件 git rm --cached "*.docx"这将从 Git 仓库中删除 .docx 文件,但不会删…...
【人工智能核心技术全景解读】从机器学习到深度学习实战
目录 🌍 前言🏛️ 技术背景与价值💔 当前技术痛点🛠️ 解决方案概述👥 目标读者说明 🧠 一、技术原理剖析📊 核心概念图解💡 核心作用讲解🔧 关键技术模块说明⚖️ 技术选…...
android-ndk开发(10): use of undeclared identifier ‘pthread_getname_np‘
1. 报错描述 使用 pthread 获取线程名字, 用到 pthread_getname_np 函数。 交叉编译到 Android NDK 时链接报错 test_pthread.cpp:19:5: error: use of undeclared identifier pthread_getname_np19 | pthread_getname_np(thread_id, thread_name, sizeof(thr…...
CAP理论:分布式系统的权衡
CAP理论:分布式系统的权衡 引言一、CAP理论的核心定义二、CAP的权衡逻辑:如何选择?三、CAP的常见误区与澄清四、CAP的实际应用场景与技术实现五、现代分布式系统对CAP的突破与演进六、CAP理论的设计建议总结 引言 在分布式系统的设计与实践中…...
【软件设计师:软件工程】11.项目管理
一、项目管理内容 项目管理是通过规划、组织、协调资源,在有限时间与预算内实现特定目标的过程,核心是平衡范围、时间、成本、质量四大要素,确保项目成功交付。 1.核心内容 项目启动目标定义:明确项目范围、交付成果及成功标准。可行性分析:评估技术、经济与风险可行性…...
遗传算法求解异构车队VRPTW问题
这里写目录标题 染色体编码设计:两种染色体编码方式一、客户排列 分割点(Giant Tour Split)1. 示例编码与解码2. 采用 客户排列 分割点 设计的特点3. 编码实现(基于Python) 二、使用整体聚类局部路由(cl…...
区块链内容创作全攻略:海报、白皮书与视频的视觉化革命
区块链内容创作全攻略:海报、白皮书与视频的视觉化革命 ——2025年去中心化叙事的技术密码与商业实践 一、区块链海报设计:视觉叙事与用户心智占领 区块链海报需在3秒内抓住观众注意力,同时传递技术内核与商业价值。核心设计法则包括&#x…...
windows的rancherDesktop修改镜像源
您好!要在Windows系统上的Rancher Desktop中修改Docker镜像源(即设置registry mirror),您需要根据Rancher Desktop使用的容器运行时(containerd或dockerd)进行配置。用户提到“allowed-image”没有效果&…...
从零开始了解数据采集(二十四)——工业4.0讲解
在全球制造业加速变革的今天,“工业4.0”成为了一个炙手可热的词汇。从德国的概念提出,到我国的积极实践,这场技术与产业的深度融合正推动制造业迈向智能化、数字化的新时代。对于企业而言,这是一次不可多得的机遇,更是…...
Java复习笔记-基础
Java复习笔记 一、什么是JDK、JRE、JVM二、Keyword-关键字三、variable-变量浮点数类型-float和double字符类型-char基本数据类型变量间运算规则基本数据类型与 String 的运算和 四、逻辑运算符五、流程控制语句关于if else 和 switchfor循环while循环do while循环 六、Array-数…...
用递归实现各种排列
为了满足字典序的输出,我采用了逐位递归的方法(每一位的所能取到的最小值都大于前一位) 1,指数型排列 #include<bits/stdc.h> using ll long long int; using namespace std; int a[10];void printp(int m) {for (int h …...
基于Stable Diffusion XL模型进行文本生成图像的训练
基于Stable Diffusion XL模型进行文本生成图像的训练 flyfish export MODEL_NAME"stabilityai/stable-diffusion-xl-base-1.0" export VAE_NAME"madebyollin/sdxl-vae-fp16-fix" export DATASET_NAME"lambdalabs/naruto-blip-captions"acceler…...