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. 简单快速:基于文本的简单协议

  2. 无连接:每次连接只处理一个请求

  3. 无状态:协议不保留之前的请求信息

  4. 灵活:可以传输任意类型的数据

  5. 支持多种请求方法:满足不同场景需求

1.4 HTTP在物联网中的应用

  1. 设备数据上报:向服务器发送传感器数据

  2. 远程配置:从服务器获取设备配置

  3. 固件升级:通过HTTP下载固件包

  4. Web控制界面:提供设备管理页面

  5. 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 代码说明

  1. WiFi连接

    • 使用WiFi.begin()连接到指定的WiFi网络

    • 单独的WiFi监控任务持续检查连接状态并在断开时重新连接

  2. HTTP功能

    • 使用HTTPClient库实现HTTP协议

    • 支持GET和POST请求

    • POST请求发送JSON格式数据

    • 自动处理HTTP响应

  3. FreeRTOS集成

    • 创建了两个任务:一个用于HTTP通信,一个用于WiFi监控

    • 任务运行在不同的核心上以提高效率

    • 使用vTaskDelay()代替delay()以确保不阻塞其他任务

  4. 多任务处理

    • HTTP任务负责定期发送HTTP请求

    • WiFi任务持续监控网络连接状态

2.2 使用说明

  1. 修改ssidpassword为你自己的WiFi配置

  2. 修改serverUrl为你的服务器地址和API端点

  3. 根据需要调整POST请求的内容和格式

  4. 请求频率可以在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服务器

  1. 新建一个文件夹作为项目目录

  2. 在该目录下创建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 路由处理
  1. 首页路由

    app.get('/', (req, res) => {res.send(htmlPage);
    });
    • 处理根路径请求

    • 直接返回HTML页面内容

  2. GET API接口

    app.get('/api/data', (req, res) => {res.json({message: '数据获取成功',receivedData: receivedData,timestamp: new Date().toISOString()});
    });
    • 返回所有存储的数据

    • 包含状态信息和时间戳

  3. POST API接口

    app.post('/api/data', (req, res) => {// 数据验证和存储res.status(201).json({message: '数据接收成功',yourData: req.body});
    });
    • 接收ESP32发来的JSON数据

    • 验证必要字段

    • 存储数据并返回确认

  4. 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 验证步骤

  1. 确保你的PC和ESP32在同一个局域网

  2. 修改ESP32代码中的serverUrl为你的PC的IP地址和端口(如http://192.168.1.100:3000/api/data

  3. 上传ESP32代码并打开串口监视器

  4. 在浏览器中访问http://localhost:3000

  5. 观察串口输出和网页显示的数据

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最佳实践与优化

  1. 安全考虑

    • 使用HTTPS替代HTTP

    • 实现API密钥验证

    • 限制请求频率

  2. 性能优化

    • 复用HTTPClient对象

    • 减少不必要的头信息

    • 使用连接池

  3. 错误处理

    • 实现自动重试机制

    • 添加超时设置

    • 记录错误日志

  4. 数据格式

    • 使用JSON进行数据交换

    • 压缩大数据量

    • 分页获取大量数据

六、常见HTTP服务器选择

  1. 本地测试

    • Node.js + Express

    • Python Flask

    • PHP内置服务器

  2. 生产环境

    • Nginx

    • Apache

    • IIS

  3. 云服务

    • AWS API Gateway

    • 阿里云API网关

    • 腾讯云API网关

七、总结与扩展

HTTP作为互联网的基础协议,与ESP32的结合为物联网设备提供了简单可靠的数据通信方案,相对于上一篇MQTT协议,HTTP协议的开发和验证更为简单,若你对MQTT开发感兴趣,可查看ESP32开发入门(六):MQTT开发实践。掌握HTTP开发后,您可以进一步:

  1. 研究HTTPS安全连接

  2. 学习WebSocket实现实时通信

  3. 探索RESTful API设计

  4. 了解gRPC等高效协议

通过本篇教程,您应该已经掌握了ESP32上HTTP开发的核心知识。实际项目中,建议从简单的原型开始,逐步增加功能复杂度,并始终考虑安全性和性能问题。

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

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

相关文章

Python 对象引用、可变性和垃圾 回收(变量不是盒子)

变量不是盒子 1997 年夏天&#xff0c;我在 MIT 学了一门 Java 课程。Lynn Andrea Stein 教授 &#xff08;一位获奖的计算机科学教育工作者&#xff0c;目前在欧林工程学院教书&#xff09;指 出&#xff0c;人们经常使用“变量是盒子”这样的比喻&#xff0c;但是这有碍于理…

局域网常用的测速工具,Iperf3使用教程

目录 下载方式 Windows Linux 使用方法&#xff1a;测试局域网带宽 步骤一&#xff1a;服务端准备 步骤二&#xff1a;客户端发起连接 步骤三&#xff1a;查看结果 参数说明 1. Iperf常用参数&#xff08;测试够用&#xff09; 2. 通用参数&#xff08;Server端和Cli…

《深入理解分布式系统》之认识分布式系统

本文是阅读深入理解分布式系统第一章认识分布式系统时的笔记。 分布式系统的特点 多进程不共享操作系统不共享时钟 分布式系统 由多个可独立运行的子系统组成。每个子系统可以独立选择运行平台。不同的运行平台存在差异&#xff0c;比如操作系统&#xff0c;硬件规格等。由…

UE5 PCG学习笔记

https://www.bilibili.com/video/BV1onUdY2Ei3/?spm_id_from333.337.search-card.all.click&vd_source707ec8983cc32e6e065d5496a7f79ee6 一、安装PCG 插件里选择以下进行安装 移动目录后&#xff0c;可以使用 Update Redirector References&#xff0c;更新下&#xff0…

工业现场ModbusTCP转EtherNETIP网关引领生物现场领新浪潮

生物质发生器是一种能够产生、培养生物的设备。客户现场需要将生物发生器连接到罗克韦尔系统&#xff0c;但是二者协议无法直接通讯&#xff0c;需要通过ModbusTCP转Ethernet/IP网关将两者进行通讯连接&#xff0c;生物质发生器以其独特的工作原理和优势&#xff0c;使得生物的…

宝蓝德中间件部署war包时,配置的绝对路径读取错误。

文章目录 问题场景解决办法宝蓝德是什么&#xff1f;&#xff1f;一、基础环境与依赖配置二、自动化部署工具链三、高可用性与集群配置四、安全与合规性措施五、产品线差异化部署六、典型部署流程示例七、运维与优化 原因1. 明确“当前工作目录”与“绝对路径”的关系2. 问题根…

Java、Python、NodeJS等开发环境安装及配置镜像加速到国内源

文章目录 Java1.Windows1.1 scoop方式安装JDK 2.Linux2.1 apt方式安装JDK2.1.1 切换JDK2.1.2 验证版本2.1.3 原理 Python1.Windows1.1 scoop方式安装Python1.2 uv方式安装Python&#xff08;推荐&#xff09; 2.Linux2.1 apt方式安装Python2.1.1 配置版本切换2.1.2 切换Python2…

Linux系统管理与编程16:PXE自动化安装部署centos7.9操作系统

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 0.准备 1&#xff09;防火墙和SELinux systemctl stop firewalld systemctl disable firewalld setenforce 0 sed -i s/^SELINUX.*/SELINUXdisabled/ /etc/selinux/config (很不好的…

MCP(Model Context Protocol)是专为LLM(大语言模型)应用设计的标准化协议

核心定义 MCP&#xff08;Model Context Protocol&#xff09;是专为LLM&#xff08;大语言模型&#xff09;应用设计的标准化协议&#xff0c;通过安全可控的方式向AI应用暴露数据和功能。主要提供以下能力&#xff1a; 标准化的上下文管理安全的功能调用接口跨平台的数据交…

Fiori学习专题三十四:Responsiveness

在这一步中&#xff0c;我们提高了应用程序的响应能力。SAPUI5应用程序可以在手机、平板电脑和台式机设备上运行&#xff0c;我们可以配置应用程序以充分利用每种场景的屏幕状态。幸运的是&#xff0c;像sap.m.Table这样的SAPUI5控件已经提供了许多我们可以使用的功能。 1.修改…

解决 TimeoutError: [WinError 10060] 在 FramePack项目中连接 Hugging Face 超时的问题

#工作记录 以下是针对 TimeoutError: [WinError 10060] 的完整排查方案&#xff0c;适用于 FramePack项目中。 &#xff08;一般该错误的发生原因请重点排查Hugging Face模型仓库受限需要登录的情形&#xff09; FramePack项目参考资料 FramePack部署&#xff08;从PyCharm解…

obj = null; 赋值null之前没有其他引用指向obj对象,那么,当obj=null时,会被垃圾回收机制立即回收吗?

不会立即回收。 具体原因是&#xff1a; 赋值 obj null; 后&#xff0c;对象变成“不可达”&#xff0c;符合垃圾回收条件&#xff0c;但垃圾回收器并不会立刻回收它。垃圾回收是CLR自动控制的非确定性过程&#xff0c;什么时候执行回收取决于系统内存压力、GC策略、分代情况…

【Ubuntu 安装Docker CE-Jenkins】

安装Docker CE(Ubuntu) Install | Docker Docs官网 使用apt仓库安装 DNS配置(可选) #手动替换 sudo vim /etc/systemd/resolved.conf #典型配置如下 [Resolve] DNS8.8.8.8 DNS114.114.114.114 FallbackDNS1.1.1.1 # 备用 DNS#sed替换 sudo sed -i /^#DNS/ {s/#DNS/DNS8.8.8…

5、开放式PLC梯形图编程组件 - /自动化与控制组件/open-plc-programming

76个工业组件库示例汇总 开放式PLC编程环境 这是一个开放式PLC编程环境的自定义组件&#xff0c;提供了一个面向智能仓储堆垛机控制的开放式PLC编程环境。该组件采用苹果科技风格设计&#xff0c;支持多厂商PLC硬件&#xff0c;具有直观的界面和丰富的功能。 功能特点 多语…

内网和外网怎么互通?外网访问内网的几种简单方式

在企业或家庭网络中&#xff0c;经常会遇到不同内网环境下网络互通问题。例如&#xff0c;当公司本地局域网内有个办公OA网站&#xff0c;在办公室内电脑上网可以登录使用&#xff0c;但在家带宽下就无法直接通信访问到。这就需要我们采取一些实用的内外网互通技巧来解决这个问…

使用大语言模型进行机器人规划(Robot planning with LLMs)

李升伟 编译 长期规划在机器人学领域可以从经典控制方法与大型语言模型在现实世界知识能力的结合中获益。 在20世纪80年代&#xff0c;机器人学和人工智能&#xff08;AI&#xff09;领域的专家提出了莫雷奇悖论&#xff0c;观察到人类看似简单的涉及移动和感知的任务&#x…

【计算机视觉】OpenCV实战项目: opencv-text-deskew:实时文本图像校正

opencv-text-deskew&#xff1a;基于OpenCV的实时文本图像校正 一、项目概述与技术背景1.1 核心功能与创新点1.2 技术指标对比1.3 技术演进路线 二、环境配置与算法原理2.1 硬件要求2.2 软件部署2.3 核心算法流程 三、核心算法解析3.1 文本区域定位3.2 角度检测优化3.3 仿射变换…

可视化图解算法33:判断是不是平衡二叉树

1. 题目 描述 输入一棵节点数为 n 的二叉树&#xff0c;判断该二叉树是否是平衡二叉树。 在这里&#xff0c;我们只需要考虑其平衡性&#xff0c;不需要考虑其是不是排序二叉树 平衡二叉树&#xff08;Balanced Binary Tree&#xff09;&#xff0c;具有以下性质&#xff1…

【Linux网络】应用层自定义协议与序列化

应用层自定义协议与序列化 应用层 我们程序员写的一个个解决我们实际问题,满足我们日常需求的网络程序,都是在应用层. 协议是一种"约定".Socket的接口,在读写数据时,都是按"字符串"的方式来发送接收的.如果我们要传输一些"结构化的数据"怎么办…

MySQL + Elasticsearch:为什么要使用ES,使用场景与架构设计详解

MySQL Elasticsearch&#xff1a;为什么要使用ES&#xff0c;使用场景与架构设计详解 前言一、MySQL Elasticsearch的背景与需求1.1 为什么要使用Elasticsearch&#xff08;ES&#xff09;&#xff1f;1.2 为什么MySQL在某些场景下不足以满足需求&#xff1f;1.3 MySQL Elas…