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

ESP-ADF wifi_service子模块wifi_ssid_manager凭证管理函数详解

目录

  • ESP-ADF wifi_service子模块wifi_ssid_manager凭证管理函数详解
    • WiFi凭证管理函数分析
      • wifi_ssid_manager_save
      • wifi_ssid_manager_erase_all
    • 内部实现机制
      • 存储策略分析
      • 内部数据流向
      • 关键辅助函数分析
      • 重要的内部辅助函数详解
        • get_stored_id_by_ssid
        • nvs_get_write_id
        • nvs_set_counter 函数
        • nvs_reset_choosen_flag
    • 应用示例
      • 常见使用场景
    • 总结

ESP-ADF wifi_service子模块wifi_ssid_manager凭证管理函数详解

版本信息: v2.7-65-gcf908721

本章节分析的源码位于 /components/wifi_service/src/wifi_ssid_manager.c 文件

WiFi凭证管理函数分析

ESP-ADF的wifi_ssid_manager模块提供了一组函数用于实现WiFi凭证的存储和管理,包括保存SSID和密码、擦除存储的凭证等功能。这些函数构成了WiFi服务的持久化存储基础,使设备能够保存和管理多个WiFi网络信息。

wifi_ssid_manager_save

wifi_ssid_manager_save函数用于保存WiFi的SSID和密码到NVS闪存。下面是其源码实现:

/*** @brief 保存WiFi SSID和密码* * 该函数完成以下主要操作:* 1. 验证SSID和密码长度是否合法* 2. 检查SSID是否已存在* 3. 确定存储位置(新增或覆盖)* 4. 将SSID和密码保存到NVS存储* 5. 更新配置信息* * 本函数在SSID数量达到上限时使用FIFO(先进先出)策略,* 即会删除最早保存的SSID以腾出空间保存新的SSID。* * @param handle WiFi SSID管理器句柄* @param ssid WiFi网络名称* @param pwd WiFi密码* @return ESP_OK表示成功,ESP_FAIL表示失败*/
esp_err_t wifi_ssid_manager_save(wifi_ssid_manager_handle_t handle, const char *ssid, const char *pwd)
{esp_err_t ret = ESP_OK;// 检查SSID和密码长度是否超出限制if (strlen(ssid) >= WIFI_SSID_MAX_LENGTH || strlen(pwd) >= WIFI_PWD_MAX_LENGTH) {ESP_LOGE(TAG, "The length of wifi ssid or password is too long");return ESP_FAIL;}AUDIO_NULL_CHECK(TAG, handle, return ESP_FAIL);// 获取当前SSID配置信息nvs_ssid_conf_t conf = {0};nvs_ssid_list_conf_get(handle, &conf);// 检查SSID是否已存在int8_t stored_id = get_stored_id_by_ssid(handle, conf.exsit_ssid_num, ssid);uint8_t key_id = 0;if (stored_id < 0) { // SSID不存在,需要新增if (conf.exsit_ssid_num < conf.max_ssid_num) {// 还有存储空间,直接添加key_id = conf.exsit_ssid_num;conf.latest_ssid = conf.exsit_ssid_num;conf.exsit_ssid_num++;} else {// 存储空间已满,使用FIFO策略key_id = nvs_get_write_id(handle, conf.exsit_ssid_num);conf.latest_ssid = key_id;}} else {// SSID已存在,直接更新key_id = stored_id;conf.latest_ssid = stored_id;}// 准备并保存WiFi信息nvs_stored_info_t info = {.cnt = 0,.choosen = false,};memcpy(info.ssid, ssid, strlen(ssid));memcpy(info.pwd, pwd, strlen(pwd));// 执行存储操作ret |= nvs_wifi_info_save(handle, key_id, &info);ret |= nvs_set_counter(handle, conf.exsit_ssid_num);ret |= nvs_ssid_list_conf_save(handle, &conf);ret |= nvs_reset_choosen_flag(handle, &conf);if (ret != ESP_OK) {ESP_LOGE(TAG, "Fail to save url to nvs, ret = 0x%x", ret);return ESP_FAIL;}return ESP_OK;
}

下面的流程图展示了wifi_ssid_manager_save函数的执行流程:

超出限制
长度合法
无效
有效
已存在
不存在
未达到
已达到
失败
成功
开始
检查SSID和密码长度
返回ESP_FAIL
检查handle是否有效
获取SSID配置信息
检查SSID是否已存在
使用已存在的ID
是否达到最大SSID数量
分配新ID并增加计数
获取最旧的ID进行覆盖
准备WiFi信息结构
保存WiFi信息到NVS
更新计数器
保存配置信息
重置所有SSID的选择标志
操作是否成功
返回ESP_OK

这个函数实现了以下几个关键特性:

  1. 自动去重:当保存已存在的SSID时,直接更新其密码
  2. 有限队列:当SSID数量达到上限时,使用FIFO策略覆盖最旧的SSID
  3. 标记最新:总是将最新保存的SSID标记为latest_ssid,便于优先连接
  4. 重置标志:保存新SSID后重置所有choosen标志,确保连接逻辑的正确性

wifi_ssid_manager_erase_all

wifi_ssid_manager_erase_all函数用于擦除所有保存的WiFi凭证。下面是其源码实现:

/*** @brief 擦除所有保存的WiFi凭证* * 该函数完成以下主要操作:* 1. 获取当前最大SSID数量限制* 2. 清除所有WiFi信息命名空间数据* 3. 清除配置命名空间数据* 4. 重置配置信息(仅保留最大SSID数量设置)* * 调用此函数后,所有保存的WiFi网络信息将被删除,* 但管理器的最大SSID数量限制会被保留。* * @param handle WiFi SSID管理器句柄* @return ESP_OK表示成功,或者错误码*/
esp_err_t wifi_ssid_manager_erase_all(wifi_ssid_manager_handle_t handle)
{AUDIO_NULL_CHECK(TAG, handle, return ESP_FAIL);esp_err_t ret = ESP_OK;// 保存最大SSID数量限制uint8_t max_ssid_num = 0;nvs_ssid_conf_t conf = {0};ret |= nvs_ssid_list_conf_get(handle, &conf);max_ssid_num = conf.max_ssid_num;// 重置配置,仅保留最大数量限制memset(&conf, 0, sizeof(nvs_ssid_conf_t));conf.max_ssid_num = max_ssid_num;// 清除所有NVS数据action_result_t result = { 0 };ret |= esp_dispatcher_execute_with_func(handle->dispatcher, nvs_action_erase_all, (void *)handle->info_nvs, NULL, &result);ret |= esp_dispatcher_execute_with_func(handle->dispatcher, nvs_action_erase_all, (void *)handle->conf_nvs, NULL, &result);// 保存重置后的配置ret |= nvs_ssid_list_conf_save(handle, &conf);if (ret != ESP_OK) {ESP_LOGE(TAG, "Fail to erase nvs flash");}return ret;
}

下面的流程图展示了wifi_ssid_manager_erase_all函数的执行流程:

无效
有效
失败
成功
开始
检查handle是否有效
返回ESP_FAIL
获取当前配置信息
保存最大SSID数量限制
重置配置结构体
还原最大SSID数量限制
清除WiFi信息命名空间
清除配置命名空间
保存重置后的配置
操作是否成功
记录错误日志
返回错误码
返回ESP_OK

这个函数的主要特点包括:

  1. 保留配置限制:清除所有凭证但保留最大SSID数量设置,保持管理器功能的一致性
  2. 全面清除:同时清除WiFi信息和配置命名空间,确保所有凭证都被删除
  3. 重置状态:重新初始化配置信息,将存储状态恢复到初始状态
  4. 错误累积:使用|=运算符累积错误码,确保任何步骤失败都能被检测到

内部实现机制

存储策略分析

WiFi凭证管理函数采用了以下存储策略:

  1. 双空间存储:使用两个NVS命名空间分别存储配置元数据和实际WiFi凭证

    • WIFI_CONF_NVS_NAMESPACE:存储配置元数据,如最大SSID数量、存储状态等
    • WIFI_INFO_NVS_NAMESPACE:存储实际的WiFi凭证(SSID和密码)
  2. FIFO替换策略:当存储空间已满时,采用先进先出策略替换最早存储的凭证

    • 使用计数器(cnt)跟踪每个SSID的存储顺序
    • 通过nvs_get_write_id函数识别最旧的SSID
  3. 自动去重:保存时自动检查SSID是否已存在,避免重复存储

    • 使用get_stored_id_by_ssid函数查找SSID是否已存在
    • 如已存在,直接更新对应的密码信息
  4. 状态标记:使用多个标志位管理凭证状态

    • latest_ssid:标记最新保存的SSID,用于优先连接
    • choosen:标记当前选择的SSID,用于跟踪连接状态

内部数据流向

凭证管理函数内部的数据流向如下:

SSID+密码
检查重复
存储满时
保存信息
更新计数
保存配置
重置标志
清除请求
获取配置
清除数据
重置配置
应用程序
wifi_ssid_manager_save
get_stored_id_by_ssid
nvs_get_write_id
nvs_wifi_info_save
nvs_set_counter
nvs_ssid_list_conf_save
nvs_reset_choosen_flag
应用程序
wifi_ssid_manager_erase_all
nvs_ssid_list_conf_get
nvs_action_erase_all
nvs_ssid_list_conf_save

关键辅助函数分析

凭证管理函数依赖几个关键的内部辅助函数:

重要的内部辅助函数详解

以下三个函数是WiFi凭证管理的重要内部组件,虽然不直接暴露给用户,但它们实现了凭证管理的核心功能:

get_stored_id_by_ssid
/*** @brief 查找指定SSID在存储中的索引ID* * 遍历所有已存储的WiFi凭证,查找与给定参数匹配的SSID。* 该函数是实现自动去重功能的核心,确保相同的SSID不会* 多次添加到存储中。* * @param handle WiFi SSID管理器句柄* @param exsit_ssid_num 当前存在的SSID数量* @param ssid 要查找的SSID字符串* @return 成功返回找到的SSID索引,失败返回ESP_FAIL(-1)*/
static int8_t get_stored_id_by_ssid(wifi_ssid_manager_handle_t handle, uint8_t exsit_ssid_num, const char *ssid)
{// 初始化信息结构体nvs_stored_info_t info = {0};// 遍历所有存储的WiFi凭证for (int i = 0; i < exsit_ssid_num; i++) {// 清空信息结构,准备读取下一个凭证memset(&info, 0, sizeof(nvs_stored_info_t));// 从存储中获取凭证信息nvs_wifi_info_get(handle, i, &info);// 快速过滤:比较SSID长度,如果不同则跳过if (strlen(info.ssid) != strlen(ssid)) {continue;}// 比较SSID内容是否相同if (strcmp(info.ssid, ssid) == 0) {ESP_LOGD(TAG, "Found the same ssid in flash, update it");return i; // 返回找到的凭证索引}}// 未找到匹配项,返回失败return ESP_FAIL;
}

该函数用于遍历已存储的所有WiFi凭证,判断指定的SSID是否已存在。它先比较SSID长度进行快速过滤,如果长度相同才进一步比较内容。这个函数在凭证保存时起到了关键作用,确保了同一网络的凭证不会重复存储,而是直接更新密码。

nvs_get_write_id
/*** @brief 获取应覆盖的WiFi凭证ID* * 当存储空间已满时,该函数用于确定应该覆盖哪一个现有的* WiFi凭证。该函数实现了FIFO(先进先出)策略,即覆盖存储时间* 最长的凭证。* * @param handle WiFi SSID管理器句柄* @param exsit_ssid_num 当前存在的SSID数量* @return 需覆盖的WiFi凭证ID*/
static uint8_t nvs_get_write_id(wifi_ssid_manager_handle_t handle, uint8_t exsit_ssid_num)
{// 初始化计数器最大值和对应的IDuint8_t max_cnt = 0, max_cnt_id = 0;nvs_stored_info_t info = {0};// 遍历所有存储的WiFi凭证for (int i = 0; i < exsit_ssid_num; i++) {// 清空信息结构体memset(&info, 0, sizeof(nvs_stored_info_t));// 获取凭证信息nvs_wifi_info_get(handle, i, &info);// 如果当前凭证的计数器值大于或等于已记录的最大值// 则更新最大计数器值和对应IDif (info.cnt >= max_cnt) {max_cnt = info.cnt;max_cnt_id = i;}}// 返回计数器值最大的凭证IDreturn max_cnt_id;
}

该函数在存储空间已满需要替换现有凭证时使用。它通过遍历所有凭证并查找计数器值最大的凭证,实现了FIFO(先进先出)替换策略。这确保了在空间不足时,始终会覆盖最早添加的WiFi凭证。

nvs_set_counter 函数
/*** @brief 递增所有WiFi凭证的计数器值* * 递增所有已存储凭证的计数器值,用于跟踪凭证的“年龄”。* 该函数是实现FIFO(先进先出)替换策略的关键部分,确保* 新添加的凭证计数器值保持最小。* * @param handle WiFi SSID管理器句柄* @param exsit_ssid_num 当前存在的SSID数量* @return 成功返回ESP_OK,失败返回ESP_FAIL*/
static esp_err_t nvs_set_counter(wifi_ssid_manager_handle_t handle, uint8_t exsit_ssid_num)
{// 初始化返回值和信息结构体esp_err_t ret = ESP_OK;nvs_stored_info_t info = {0};// 遍历所有存在的WiFi凭证for (int i = 0; i < exsit_ssid_num; i++) {// 清空信息结构体,准备读取下一个凭证memset(&info, 0, sizeof(nvs_stored_info_t));// 从存储中获取凭证信息,并累积错误码ret |= nvs_wifi_info_get(handle, i, &info);// 将计数器值递增1,这是实现FIFO策略的关键info.cnt ++;// 保存更新后的凭证信息,并累积错误码ret |= nvs_wifi_info_save(handle, i, &info);}// 检查操作过程中是否有错误发生if (ret != ESP_OK) {ESP_LOGE(TAG, "Fail to set counter");return ESP_FAIL;}// 所有操作成功,返回ESP_OKreturn ESP_OK;
}

该函数的作用是递增所有已存储WiFi凭证的计数器值,是实现FIFO替换策略的关键辅助函数。它确保了计数器值能准确反映凭证的“年龄”。

nvs_reset_choosen_flag

重置所有凭证的选择标志

  • 确保连接逻辑的正确性
  • 防止多个凭证同时被标记为已选择

应用示例

下面是一个使用WiFi凭证管理函数的完整示例,展示了这些函数在实际应用中的使用方式:

#include <string.h>
#include "esp_log.h"
#include "wifi_ssid_manager.h"static const char *TAG = "WIFI_CRED_EXAMPLE";// 凭证管理示例函数
void wifi_credential_management_example(void)
{// 创建WiFi SSID管理器,最多保存5个SSIDwifi_ssid_manager_handle_t mgr = wifi_ssid_manager_create(5);if (mgr == NULL) {ESP_LOGE(TAG, "创建WiFi SSID管理器失败");return;}// 保存多个WiFi凭证ESP_LOGI(TAG, "保存WiFi凭证1");esp_err_t ret = wifi_ssid_manager_save(mgr, "HomeWiFi", "home123456");if (ret != ESP_OK) {ESP_LOGE(TAG, "保存WiFi凭证1失败");}ESP_LOGI(TAG, "保存WiFi凭证2");ret = wifi_ssid_manager_save(mgr, "OfficeWiFi", "office789");if (ret != ESP_OK) {ESP_LOGE(TAG, "保存WiFi凭证2失败");}ESP_LOGI(TAG, "保存WiFi凭证3");ret = wifi_ssid_manager_save(mgr, "CafeWiFi", "cafe2023");if (ret != ESP_OK) {ESP_LOGE(TAG, "保存WiFi凭证3失败");}// 显示当前存储的所有WiFi凭证ESP_LOGI(TAG, "显示所有存储的WiFi凭证:");wifi_ssid_manager_list_show(mgr);// 更新已存在的WiFi凭证密码ESP_LOGI(TAG, "更新HomeWiFi的密码");ret = wifi_ssid_manager_save(mgr, "HomeWiFi", "newhome888");if (ret != ESP_OK) {ESP_LOGE(TAG, "更新WiFi密码失败");}// 尝试获取最佳WiFi配置(通常会扫描并匹配信号最强的网络)wifi_config_t wifi_config = {0};ret = wifi_ssid_manager_get_best_config(mgr, &wifi_config);if (ret == ESP_OK) {ESP_LOGI(TAG, "获取到最佳WiFi配置: SSID=%s", (char *)wifi_config.sta.ssid);} else {ESP_LOGE(TAG, "获取最佳WiFi配置失败");}// 获取最新保存的WiFi配置memset(&wifi_config, 0, sizeof(wifi_config_t));ret = wifi_ssid_manager_get_latest_config(mgr, &wifi_config);if (ret == ESP_OK) {ESP_LOGI(TAG, "获取到最新WiFi配置: SSID=%s", (char *)wifi_config.sta.ssid);} else {ESP_LOGE(TAG, "获取最新WiFi配置失败");}// 擦除所有WiFi凭证ESP_LOGI(TAG, "擦除所有WiFi凭证");ret = wifi_ssid_manager_erase_all(mgr);if (ret != ESP_OK) {ESP_LOGE(TAG, "擦除WiFi凭证失败");}// 确认所有凭证已被擦除ESP_LOGI(TAG, "确认所有凭证已被擦除:");wifi_ssid_manager_list_show(mgr);// 销毁WiFi SSID管理器ESP_LOGI(TAG, "销毁WiFi SSID管理器");wifi_ssid_manager_destroy(mgr);
}void app_main(void)
{// 初始化NVS闪存(通常在应用程序开始时执行)esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {// NVS分区被充满或发现新版本,需要擦除处理ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK(ret);// 执行凭证管理示例wifi_credential_management_example();
}

在这个示例中,我们演示了WiFi凭证管理函数的典型用法:

  1. 创建管理器并设置最大存储数量
  2. 保存多个WiFi凭证(包括新增和更新)
  3. 列出当前存储的所有凭证
  4. 获取最佳配置和最新配置
  5. 擦除所有凭证
  6. 销毁管理器释放资源

常见使用场景

WiFi凭证管理函数在以下场景中特别有用:

  1. 多网络管理:设备需要在多个WiFi网络间切换,如家庭/办公室/公共场所
  2. 配网后存储:通过配网(如SmartConfig、蓝牙配网等)获取的WiFi凭证需要持久化存储
  3. 备用网络:存储多个备用网络,当主网络不可用时自动切换
  4. 网络优先级:基于信号强度或保存顺序确定连接优先级
  5. 恢复出厂设置:需要清除所有存储的网络凭证

总结

ESP-ADF的WiFi凭证管理函数提供了一套完整的接口,用于管理WiFi网络凭证的存储、检索和清除。这些函数具有以下几个关键特性:

  1. 有限存储管理:通过最大SSID数量限制和FIFO替换策略,有效管理有限的存储空间
  2. 自动去重:保存时自动检查SSID是否已存在,避免重复存储
  3. 优先级管理:通过latest_ssid和choosen标志管理网络连接优先级
  4. 持久化存储:利用NVS闪存实现WiFi凭证的持久化存储,断电不丢失
  5. 完整的生命周期:提供从保存到擦除的完整生命周期管理

通过合理使用这些凭证管理函数,开发者可以轻松实现设备的多网络管理,提升用户体验和设备连接可靠性。

相关文章:

ESP-ADF wifi_service子模块wifi_ssid_manager凭证管理函数详解

目录 ESP-ADF wifi_service子模块wifi_ssid_manager凭证管理函数详解WiFi凭证管理函数分析wifi_ssid_manager_savewifi_ssid_manager_erase_all 内部实现机制存储策略分析内部数据流向关键辅助函数分析重要的内部辅助函数详解get_stored_id_by_ssidnvs_get_write_idnvs_set_cou…...

数据分析预备篇---NumPy数组

NumPy是数据分析时常用的库,全称为Numerical Python,是很多数据或科学相关Python包的基础,包括pandas,scipy等等,常常被用于科学及工程领域。NumPy最核心的数据结构是ND array,意思是N维数组。 #以下是一个普通列表的操作示例:arr = [5,17,3,26,31]#打印第一个元素 prin…...

解决VirtualBox中虚拟机(ubuntu)与主机(windows)之间互相复制粘贴(文本)

一.开始的设置 1.在VirtualBox中打开设置&#xff0c;常规中修改主机与虚拟机交互设置 2.虚拟机关闭状态下&#xff0c;存储中选中控制器SATA&#xff0c;勾选‘使用主机输入输出’ 3.选中操作系统对应的虚拟文件&#xff0c;.vdi文件&#xff0c;勾选右边的固态驱动器。 4.启…...

单细胞RNA测序数据分析与可视化:从基础原理到高级应用

引言 单细胞RNA测序&#xff08;scRNA-seq&#xff09;技术的出现彻底改变了我们研究复杂生物系统的方式&#xff0c;使科学家能够在前所未有的精细水平上解析细胞异质性。传统的bulk RNA测序只能捕获细胞群体的平均表达特征&#xff0c;而单细胞转录组测序允许我们检测每个细…...

嵌入式硬件篇---UART

文章目录 前言1. UART协议基础1.1 物理层特性两根信号线无时钟信号电平标准TTL UARTRS-232 1.2 数据帧格式1.3 波特率计算波特率 2. STM32F103RCT6的UART配置2.1 硬件连接2.2 CubeMX配置启用USART1引脚分配中断启用&#xff08;可选&#xff09; 3. HAL库代码实现3.1 UART初始化…...

C# 通过ConfigurationManager读写配置文件App.Config

目录 简述代码描述一、构建App.config二、调用代码1、代码步骤说明2、输出结果说明 简述 App.config 是 C#中最常用的配置文件类型。 通常位于项目的根目录中&#xff0c;以 XML 格式存储配置信息。App.config 文件可以包含多个配置节&#xff0c;如 appSettings、connectionS…...

Python3安装HTMLTestRunner

1.下载HTMLTestRunner地址&#xff1a;http://tungwaiyip.info/software/HTMLTestRunner.html 2.下载的HTMLTestRunner.py是针对python2写的&#xff0c;所以需要改成python3适合的内容&#xff1a; 问题1&#xff1a;No module named StringIO&#xff0c; 原因&#xff1a;py…...

图形化编程革命:iVX携手AI 原生开发范式

一、技术核心&#xff1a;图形化编程的底层架构解析 1. 图形化开发的效率优势&#xff1a;代码量减少 72% 的秘密 传统文本编程存在显著的信息密度瓶颈。以 "按钮点击→条件判断→调用接口→弹窗反馈" 流程为例&#xff0c;Python 实现需定义函数、处理缩进并编写 …...

GC垃圾回收

Gc是语言提供的自动的内存管理机制&#xff0c;自动释放不需要的内存对象&#xff0c;让出存储器资源。 Go语言变革&#xff1a; V1.5的三色并发标记法 V1.5的三色并发标记为什么需要STW V1.5的三色标记为什么需要屏障机制(“强-弱”&#xff0c;三色不变式、插入屏障、删除屏障…...

“多端多接口多向传导”空战数据链体系——从异构融合架构到抗毁弹性网络的系统性设计

“多端多接口多向传导”空战数据链体系——从异构融合架构到抗毁弹性网络的系统性设计 文章目录 “多端多接口多向传导”空战数据链体系——从异构融合架构到抗毁弹性网络的系统性设计第一章 引言:空战数据链体系的范式革新1.1 空战数据链的演进逻辑1.2 新架构的核心理论价值1…...

Unity3D仿星露谷物语开发42之粒子系统

1、目标 使用例子系统&#xff0c;实现割草后草掉落的特效。 通过PoolManager获取特效预制体&#xff0c;通过VFXManager来触发特效。 2、配置例子特效 在Hierarchy -> PersistentScene下创建新物体命名为Reaping。 给该物体添加Particle System组件。 配置例子系统参数…...

python打卡训练营打卡记录day22

复习日 仔细回顾一下之前21天的内容&#xff0c;没跟上进度的同学补一下进度。 作业&#xff1a; 自行学习参考如何使用kaggle平台&#xff0c;写下使用注意点&#xff0c;并对下述比赛提交代码 kaggle泰坦尼克号人员生还预测 导入数据 # 导入所需库 import pandas as pd impor…...

网络编程(一)网络编程入门

本节课学习TCP客户端和服务器端编程架构&#xff0c;其分为分为C/S&#xff08;客户端/服务器模式&#xff09;和B/S&#xff08;浏览器/服务器架构模式&#xff09;两种模式。接下来我们分别了解这两种模式 C/S模式 C/S模式&#xff1a;服务器首先先启动&#xff0c;并根据客…...

华为IP(6)

VLAN聚合 VLAN聚合产生的技术背景 在一般是三层交换机中&#xff0c;通常采用一个VLAN接口的方式实现广播域之间的互通&#xff0c;这在某些情况下导致了IP地址的浪费 因为一个VLAN对应的子网中&#xff0c;子网号、子网广播地址、子网网关地址不能用作VLAN内的主机IP地址&a…...

初探机器学习与深度学习

本文以水果摊销量预测为例&#xff0c;揭示机器学习通过数据训练模型的核心逻辑&#xff0c;对比传统编程规则驱动模式。解析分类&#xff08;疾病诊断&#xff09;与回归&#xff08;房价预测&#xff09;两大任务的技术本质&#xff0c;类比前端开发中的类型定义与图表拟合。…...

3. 仓颉 CEF 库封装

文章目录 1. capi 使用说明2. Cangjie CEF2. 1实现目标 3. 实现示例 1. capi 使用说明 根据上一节 https://blog.csdn.net/qq_51355375/article/details/147880718?spm1011.2415.3001.5331 所述&#xff0c; cefcapi 是libcef 共享库导出一个 C API, 而以源代码形式分发的 li…...

Linux-TCP套接字编程简易实践:实现EchoServer与远程命令执行及自定义协议(反)序列化

一.TCP Socket常用API 1.1socket() NAMEsocket - create an endpoint for communicationSYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int socket(int domain, int type, int protocol); socket()打开一个网络通讯端口,如果…...

缓存(3):本地缓存作用 及 数据一致性 实现策略

概述 CAP 什么是CAP CAP理论&#xff0c;指的是在一个分布式系统中&#xff0c; Consistency&#xff08;一致性&#xff09;、 Availability&#xff08;可用性&#xff09;、Partition tolerance&#xff08;分区容错性&#xff09;&#xff0c;三者不可得兼。 三者关系如…...

【leetcode】《BFS扫荡术:如何用广度优搜索征服岛屿问题》

前言 &#x1f31f;&#x1f31f;本期讲解关于力扣的几篇题解的详细介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…...

vue中理解MVVM

理解 在 Vue 中&#xff0c;MVVM&#xff08;Model-View-ViewModel&#xff09; 是其核心设计思想之一&#xff0c;它帮助实现了数据驱动的视图更新和良好的代码结构分离。我们来具体解析 Vue 是如何实现 MVVM 模式的。 &#x1f310; MVVM 是什么&#xff1f; 角色含义Vue…...

[工具]B站缓存工具箱 (By 郭逍遥)

&#x1f4cc; 项目简介 B站缓存工具箱是一个多功能的B站缓存工具&#xff0c;包含视频下载、缓存重载、文件合并及系统设置四大核心功能。基于yutto开发&#xff0c;采用图形化界面操作&#xff0c;极大简化B站资源获取与管理流程。 工具可以直接将原本缓存的视频读取&#…...

Docker Compose 完全指南:从入门到生产实践

Docker Compose 完全指南&#xff1a;从入门到生产实践 1. Docker Compose 简介与核心价值 Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。通过一个 YAML 文件来配置应用的服务&#xff0c;只需简单命令就能创建和启动所有服务。 核心优势&#xff1a;…...

《Redis应用实例》学习笔记,第二章:缓存二进制数据

前言 最近在学习《Redis应用实例》&#xff0c;这本书并没有讲任何底层&#xff0c;而是聚焦实战用法&#xff0c;梳理了 32 种 Redis 的常见用法。我的笔记在 Github 上&#xff0c;用 Jupyter 记录&#xff0c;会有更好的阅读体验&#xff0c;作者的源码在这里&#xff1a;h…...

ARM GIC(七)亲和路由:GICD_IROUTER寄存器具体如何与MPIDR配合使用?

ARM GIC&#xff08;一&#xff09; GIC V3架构基础学习笔记 完善亲和路由章节。 一、MPIDR MPIDR&#xff08;Multiprocessor Affinity Register&#xff09;寄存器在ARM架构中用于标识处理器的亲和性信息&#xff0c;这对于中断处理非常重要&#xff0c;特别是在多处理器系…...

stm32之SPI

目录 1.SPI通信协议1.1 简介1.2 硬件电路1.3 移位示意图1.4 SPI时序基本单元1.5 SPI时序 2.W25Q642.1 简介2.2 硬件电路2.3 框图2.3.1 结构介绍2.3.2 混淆 2.4 Flash操作注意事项2.4.1 写操作2.4.2 读取操作 2.5 芯片手册补充2.5.1 状态寄存器2.5.2 指令集 3.软件操作W25Q644.S…...

数据库事务以及JDBC实现事务

一、数据库事务 数据库事务&#xff08;Database Transaction&#xff09;是数据库管理系统中的一个核心概念&#xff0c;它代表一组操作的集合&#xff0c;这些操作要么全部执行成功&#xff0c;要么全部不执行&#xff0c;即操作数据的最小执行单元&#xff0c;保证数据库的…...

C语言_函数调用栈的汇编分析

在 C 语言的底层实现中&#xff0c;函数调用栈是程序运行时内存管理的核心机制。它不仅负责函数间的控制转移&#xff0c;还管理局部变量、参数传递和返回值。本文将结合 C 语言代码和 x86-64 汇编指令&#xff0c;深入解析函数调用栈的工作原理。 一、函数调用栈的基本概念 …...

单片机调用printf概率性跑飞解决方法

最近移植软件到不同平台的单片机上时&#xff0c;遇到了软件概率性跑飞的问题&#xff0c;分析后原因均指向和printf相关的库函数&#xff08;包括sprintf, vsnsprinft&#xff09;&#xff0c;在任务里调用这些函数就有概率在ucos切换任务时跑飞&#xff08;中断&#xff09;。…...

无人机空中物流优化:用 Python 打造高效配送模型

友友们好! 我是Echo_Wish,我的的新专栏《Python进阶》以及《Python!实战!》正式启动啦!这是专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会…...

【RP2350】香瓜树莓派RP2350之低功耗

本文最后修改时间&#xff1a;2025年05月10日 01:57 一、本节简介 本节以树莓派pico2开发板为例&#xff0c;举例如何写一个低功耗驱动。 二、实验平台 1、硬件平台 1&#xff09;树莓派pico2开发板 ①树莓派pico2开发板&#xff08;作为仿真器&#xff09; ②micro usb数…...

招行数字金融挑战赛数据赛道赛题一

赛题描述&#xff1a;根据提供的用户行为数据&#xff0c;选手需要分析用户行为特征与广告内容的匹配关系&#xff0c;准确预测用户对测试集广告的点击情况&#xff0c;通过AUC计算得分。 得分0.6120&#xff0c;排名60。 尝试了很多模型都没有能够提升效果&#xff0c;好奇大…...

仿真生成激光干涉包裹相位数据-用于深度学习训练!

该MATLAB/Octave代码实现了论文[1]中提出的相位提取算法,用于从灰度条纹图案中提取包裹相位图(相位值在-π到+π之间)。代码首先生成模拟的条纹图案,包含背景光、调制光和相位分布,并加入高斯噪声。随后,通过N步相移算法估计背景光和调制光,并计算包裹相位。结果显示包括…...

命令行解释器中shell、bash和zsh的区别

命令行解释器&#xff08;Command Line Interpreter&#xff09;是一个程序&#xff0c;它的主要作用是接收用户输入的命令&#xff0c;并执行相应的操作。它充当了用户与操作系统内核之间的桥梁。 一、什么是 Shell&#xff1f; Shell 是一个通用术语&#xff0c;指的是 命令…...

SQL 数据库监控:SQL语句监控工具与实践案例

SQL 数据库监控&#xff1a;SQL语句监控工具与实践案例 SQL语句监控的主要方法 SQL监控主要通过以下几种方式实现&#xff1a; 数据库内置监控功能&#xff1a;大多数数据库系统提供内置的SQL监控工具数据库性能视图/系统表&#xff1a;通过查询特定的系统视图获取SQL执行信…...

招行数字金融挑战赛数据分析赛带赛题二

赛题描述&#xff1a;根据提供的脱敏资讯新闻数据&#xff0c;选手需要对提供的训练集进行特征工程&#xff0c;构建资讯分类模型&#xff0c;对与测试集进行准确的新闻分类。 最终得分&#xff1a;0.8120。十二点关榜没看到排名&#xff0c;估算100&#xff1f; 训练集很小&am…...

llama.cpp初识

Llama.cpp&#xff1a;赋能本地大语言模型推理的核心引擎及其应用场景 引言&#xff1a;Llama.cpp 是什么&#xff1f; 大型语言模型 (LLM) 的兴起正在深刻改变人机交互和信息处理的方式。然而&#xff0c;这些强大的模型通常需要巨大的计算资源&#xff0c;使得它们在云端之…...

【EBNF】EBNF:扩展巴克斯-诺尔范式文件格式与实用写法详解

EBNF&#xff1a;扩展巴克斯-诺尔范式文件格式与实用写法详解 一、什么是 EBNF&#xff1f; Extended Backus-Naur Form (EBNF)是一种形式化的语法&#xff0c;用于指定编程语言或其他形式化语言的结构。它是Backus-Naur形式&#xff08;BNF&#xff09;的扩展&#xff0c;最初…...

Go语言运算符详解

文章目录 1. 算术运算符2. 关系运算符3. 逻辑运算符4. 位运算符5. 赋值运算符6. 其他运算符运算符优先级注意事项 Go语言提供了与其他语言类似的运算符&#xff0c;包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符等。这些运算符即可满足基本的运算需求。 1. 算…...

MySQL用户管理

目录 一、用户用户信息创建用户删除用户从远端登录修改用户密码 二、数据库的权限给用户授权回收权限 与Linux操作系统类似&#xff0c;MySQL中也有超级用户和普通用户之分。&#xff0c;如果一个用户只需要访问MySQL中的某一个数据库&#xff0c;甚至数据库中的某一个表&#…...

视频编解码学习三之显示器续

一、现在主流的显示器是LCD显示器吗&#xff1f; 是的&#xff0c;现在主流的显示器仍然是 LCD&#xff08;液晶显示器&#xff0c;Liquid Crystal Display&#xff09;&#xff0c;但它已经细分为多种技术类型&#xff0c;并和其他显示技术&#xff08;如OLED&#xff09;形成…...

VSCode1.101.0便携版|中英文|编辑器|安装教程

软件介绍 Visual Studio Code是微软推出的一个强大的代码编辑器&#xff0c;功能强大&#xff0c;操作简单便捷&#xff0c;还有着良好的用户界面&#xff0c;设计得很人性化&#xff0c;旨在为所有开发者提供一款专注于代码本身的免费的编辑器。 软件安装 1、 下载安装包…...

Scala 中累加器的创建与使用格式详解

1. 内置累加器的创建与使用格式 1.1 创建内置累加器 // 通过 SparkContext 创建 val acc sc.longAccumulator("累加器名称") // Long 类型&#xff08;默认初始值 0&#xff09; val accDouble sc.doubleAccumulator("累加器名称") // Double 类型&a…...

【DNDC模型】双碳目标下DNDC模型建模方法及在土壤碳储量、温室气体排放、农田减排、土地变化、气候变化中的应用

由于全球变暖、大气中温室气体浓度逐年增加等问题的出现&#xff0c;“双碳”行动特别是碳中和已经在世界范围形成广泛影响。国家领导人在多次重要会议上讲到&#xff0c;要把“双碳”纳入经济社会发展和生态文明建设整体布局。同时&#xff0c;提到要把减污降碳协同增效作为促…...

深入剖析缓存与数据库一致性:Java技术视角下的解决方案与实践

一、缓存与数据库一致性问题根源 读写分离的架构矛盾 缓存作为数据库的“副本”&#xff0c;天然存在数据同步延迟。 高频读写场景下&#xff0c;缓存与数据库的更新顺序、失败重试等操作易引发不一致。 经典问题场景 场景1&#xff1a;先更新数据库&#xff0c;再删除缓存。…...

Anaconda环境中conda与pip命令的区别

文章目录 conda与pip的基本区别在Anaconda环境中的实际差异安装包环境管理依赖解决示例最佳实践建议 常见问题解答 conda与pip的基本区别 包来源与生态系统 conda&#xff1a;从Anaconda默认仓库或conda-forge等渠道获取包 不仅管理Python包&#xff0c;还能管理非Python依赖&…...

使用FastAPI和React以及MongoDB构建全栈Web应用05 FastAPI快速入门

一、FastAPI概述 1.1 什么是FastAPI FastAPI is a modern, high-performance Python web framework designed for building APIs. It’s rapidly gaining popularity due to its ease of use, speed, and powerful features. Built on top of Starlette, FastAPI leverages a…...

每日c/c++题 备战蓝桥杯(P1002 [NOIP 2002 普及组] 过河卒)

洛谷P1002 [NOIP 2002 普及组] 过河卒 题解 题目描述 过河卒是一道经典的动态规划题目。题目大意是&#xff1a;一个卒子从棋盘左上角(0,0)出发&#xff0c;要走到右下角(n,m)&#xff0c;棋盘上有一个马在(x,y)位置&#xff0c;卒子不能经过马所在位置及其周围8个位置。求卒…...

kubectl系列(十二):查询pod的resource 配置

在 Kubernetes 中&#xff0c;可以通过 kubectl 命令快速查询 Pod 的资源请求&#xff08;requests&#xff09;和限制&#xff08;limits&#xff09;配置。以下是多种方法实现这一目标&#xff1a; 1. 查看 Pod 的资源请求和限制&#xff08;基础版&#xff09; 使用 kubec…...

前端面试2

1. 面试准备 1. 建立自己的知识体系 思维导图ProcessOn框架Vue elementUI自查 https://zh.javascript.info/ 借鉴 https://juejin.cn/post/6844904103504527374http://conardli.top/blog/article/https://github.com/mqyqingfeng/Bloghttp://47.98.159.95/my_blog/#html 2.技能…...

使用 Java 反射动态加载和操作类

Java 的反射机制(Reflection)是 Java 语言的一大特色,它允许程序在运行时检查、加载和操作类、方法、字段等元信息。通过 java.lang.Class 和 java.lang.reflect 包,开发者可以动态加载类、创建实例、调用方法,甚至在运行时构造新类。反射是 Java 灵活性的核心,广泛应用于…...