【ESP32】ESP-IDF开发 | WiFi开发 | HTTPS服务器 + 搭建例程
1. 简介
1.1 HTTPS
HTTPS(HyperText Transfer Protocol over Secure Socket Layer),全称安全套接字层超文本传输协议,一般理解为HTTP+SSL/TLS,通过SSL证书来验证服务器的身份,并为浏览器和服务器之间的通信进行加密。该协议使用443端口进行通信。
它解决的是HTTP协议明文传输的不安全性,HTTPS协议在数据进行传输之前,对数据进行加密,然后再发送到服务器。这样,就算数据被第三者所截获,但是由于数据是加密的,所以你的个人信息仍然是安全的。
1.2 SSL/TLS
SSL(Secure Socket Layer,安全套接字层):1994年为 Netscape 所研发,SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。
TLS(Transport Layer Security,传输层安全):其前身是 SSL,它最初的几个版本(SSL 1.0、SSL 2.0、SSL 3.0)由网景公司开发,1999年从 3.1 开始被 IETF 标准化并改名,发展至今已经有 TLS 1.0、TLS 1.1、TLS 1.2 三个版本。SSL 3.0和TLS 1.0由于存在安全漏洞,已经很少被使用到。
1.3 通信流程

2. 例程
因为HTTPS相对于HTTP只是多了加密的过程,所以例程大体是沿用前一篇文章的代码,所以下面只会讲解加密部分的代码。
2.1 函数API
2.1.1 启动服务器
esp_err_t httpd_ssl_start(httpd_handle_t *handle, httpd_ssl_config_t *config)
- handle:HTTPS句柄;
- config:服务器配置。
struct httpd_ssl_config {httpd_config_t httpd;const uint8_t *servercert;size_t servercert_len;const uint8_t *cacert_pem;size_t cacert_len;const uint8_t *prvtkey_pem;size_t prvtkey_len;bool use_ecdsa_peripheral;uint8_t ecdsa_key_efuse_blk;httpd_ssl_transport_mode_t transport_mode;uint16_t port_secure;uint16_t port_insecure;bool session_tickets;bool use_secure_element;esp_https_server_user_cb *user_cb;void *ssl_userdata;esp_tls_handshake_callback cert_select_cb;const char** alpn_protos;
};
配置结构体的内容比较多,ESP-IDF也提供了HTTPD_SSL_CONFIG_DEFAULT宏进行快速默认配置,所以下面只解释一些常用的配置:
- servercert:服务器证书;
- servercert_len:服务器证书长度;
- cacert_pem:CA证书;
- cacert_len:CA证书长度;
- prvtkey_pem:私钥;
- prvtkey_len:私钥长度;
- port_secure:安全端口,即采用https访问时的端口,默认为443;
- port_insecure:非安全端口,即采用http访问时的端口,默认为80;
- user_cb:用户回调,主要用于客户端连接或断开时进行自定义处理;
2.2 代码
#include "freertos/FreeRTOS.h"#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "sys/socket.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "netdb.h"
#include "arpa/inet.h"
#include "esp_https_server.h"
#include "esp_tls.h"
#include "mbedtls/base64.h"#include <string.h>#define TAG "app"static httpd_handle_t server_handle;static const uint8_t servercert[] =
"-----BEGIN CERTIFICATE-----\n\
MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL\n\
BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx\n\
MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ\n\
UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n\
ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T\n\
sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k\n\
qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd\n\
GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4\n\
sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb\n\
jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/\n\
ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud\n\
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3\n\
emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY\n\
W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx\n\
bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN\n\
ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl\n\
hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo=\n\
-----END CERTIFICATE-----";static const uint8_t prvkey[] =
"-----BEGIN PRIVATE KEY-----\n\
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH\n\
JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw\n\
h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT\n\
aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al\n\
3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg\n\
0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB\n\
vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui\n\
f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9\n\
Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y\n\
JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX\n\
49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc\n\
+3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6\n\
pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D\n\
0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG\n\
YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV\n\
MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL\n\
CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin\n\
7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1\n\
noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8\n\
4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g\n\
Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/\n\
nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3\n\
q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2\n\
lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB\n\
jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr\n\
v/t+MeGJP/0Zw8v/X2CFll96\n\
-----END PRIVATE KEY-----";static const char index_html[] = " \
<!DOCTYPE html> \
<html> \
<head> \
<meta charset=\"utf-8\"> \
<title>index</title> \
</head> \
\
<body> \<h1>Hello from ESP32</h1> \
</body> \<form action=\"/hello\" method=\"post\"> \<label for=\"name\">What's your name:</label> \<input type=\"text\" id=\"name\" name=\"name\" required> \<input type=\"submit\" value=\"OK\"></button> \</form> \
</html> \
";static const char hello_html_template[] = " \
<!DOCTYPE html> \
<html> \
<head> \
<meta charset=\"utf-8\"> \
<title>hello</title> \
</head> \
\
<body> \<h1>Oh, Hello %s</h1> \
</body> \
\
</html> \
";static esp_err_t index_get_handler(httpd_req_t *req)
{/* 获取Host信息 */size_t buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1;if (buf_len > 1) {char *buf = malloc(buf_len);if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {ESP_LOGI(TAG, "Get request to host: %s", buf);}free(buf);}/* 回复数据包 */httpd_resp_sendstr(req, index_html);return ESP_OK;
}static const httpd_uri_t index_uri = {.uri = "/index",.method = HTTP_GET,.handler = index_get_handler,.user_ctx = NULL
};static esp_err_t hello_post_handler(httpd_req_t *req)
{/* 获取Host信息 */size_t buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1;if (buf_len > 1) {char *buf = malloc(buf_len);if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {ESP_LOGI(TAG, "Post request to host: %s", buf);}free(buf);}/* 获取内容长度 */int len = 0;{char *buf = malloc(128);memset(buf, 0, 128);if (httpd_req_get_hdr_value_str(req, "Content-Length", buf, 128) != ESP_OK) {ESP_LOGE(TAG, "Get content length failed");return ESP_FAIL;}len = atoi(buf) + 1;free(buf);}/* 获取表单数据 */char *buf = malloc(len);memset(buf, 0, len);if (httpd_req_recv(req, buf, len) <= 0) {ESP_LOGE(TAG, "Receive request content failed");return ESP_FAIL;}if (strstr(buf, "name=") == NULL) {ESP_LOGE(TAG, "Can't found fleid \"name\"");free(buf);return ESP_FAIL;}/* 发送数据 */char *hello_html = malloc(1024);snprintf(hello_html, 1024, hello_html_template, buf + strlen("name="));httpd_resp_sendstr(req, hello_html);free(buf);free(hello_html);return ESP_OK;
}static const httpd_uri_t hello_uri = {.uri = "/hello",.method = HTTP_POST,.handler = hello_post_handler,.user_ctx = NULL
};static void print_peer_cert_info(const mbedtls_ssl_context *ssl)
{const mbedtls_x509_crt *cert;const size_t buf_size = 1024;char *buf = calloc(buf_size, sizeof(char));if (buf == NULL) {ESP_LOGE(TAG, "Out of memory - Callback execution failed!");return;}cert = mbedtls_ssl_get_peer_cert(ssl);if (cert != NULL) {mbedtls_x509_crt_info((char *) buf, buf_size - 1, " ", cert);ESP_LOGI(TAG, "Peer certificate info:\n%s", buf);} else {ESP_LOGW(TAG, "Could not obtain the peer certificate!");}free(buf);
}static void https_server_user_callback(esp_https_server_user_cb_arg_t *user_cb)
{mbedtls_ssl_context *ssl_ctx = NULL;switch(user_cb->user_cb_state) {case HTTPD_SSL_USER_CB_SESS_CREATE:int sockfd = -1;esp_err_t esp_ret;esp_ret = esp_tls_get_conn_sockfd(user_cb->tls, &sockfd);if (esp_ret != ESP_OK) {ESP_LOGE(TAG, "Error in obtaining the sockfd from tls context");break;}ESP_LOGI(TAG, "Socket FD: %d", sockfd);ssl_ctx = (mbedtls_ssl_context *) esp_tls_get_ssl_context(user_cb->tls);if (ssl_ctx == NULL) {ESP_LOGE(TAG, "Error in obtaining ssl context");break;}ESP_LOGI(TAG, "Current Ciphersuite: %s", mbedtls_ssl_get_ciphersuite(ssl_ctx));break;case HTTPD_SSL_USER_CB_SESS_CLOSE:ssl_ctx = (mbedtls_ssl_context *) esp_tls_get_ssl_context(user_cb->tls);if (ssl_ctx == NULL) {ESP_LOGE(TAG, "Error in obtaining ssl context");break;}print_peer_cert_info(ssl_ctx);break;default:break;}
}static void event_handler(void* arg,esp_event_base_t event_base,int32_t event_id,void* event_data)
{if (event_base == IP_EVENT) {if (event_id == IP_EVENT_STA_GOT_IP) {/* 配置 */httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();conf.servercert = servercert;conf.servercert_len = sizeof(servercert);conf.prvtkey_pem = prvkey;conf.prvtkey_len = sizeof(prvkey);conf.user_cb = https_server_user_callback;/* 启动服务器 */esp_err_t ret = httpd_ssl_start(&server_handle, &conf);if (ESP_OK != ret) {ESP_LOGI(TAG, "Error starting server!");return;}/* 注册URI */httpd_register_uri_handler(server_handle, &index_uri);httpd_register_uri_handler(server_handle, &hello_uri);ip_event_got_ip_t *data = event_data;ESP_LOGI(TAG, "HTTPS server started at https://" IPSTR "/index", IP2STR(&(data->ip_info.ip)));}} else if (event_base == WIFI_EVENT) {if (event_id == WIFI_EVENT_STA_DISCONNECTED) {static uint32_t retry = 1;ESP_LOGW(TAG, "Try reconnect WiFi, retry %lu", retry);vTaskDelay(500 / portTICK_PERIOD_MS);esp_wifi_connect();retry++;} else if (event_id == WIFI_EVENT_STA_START) {esp_wifi_connect();}}
}int app_main()
{/* 初始化NVS */esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ESP_ERROR_CHECK(nvs_flash_init());}/* 初始化WiFi协议栈 */ESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_create_default_wifi_sta();wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&event_handler,NULL,NULL));ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,IP_EVENT_STA_GOT_IP,&event_handler,NULL,NULL));wifi_config_t wifi_config = {.sta = {.ssid = "Your SSID",.password = "Your Password",.threshold.authmode = WIFI_AUTH_WPA_WPA2_PSK,},};ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));ESP_ERROR_CHECK(esp_wifi_start());return 0;
}
https服务器需要配置自己的公钥和私钥,我这里使用的是官方例程给的,当然也可以自己生成;例程中也注册了用户回调,来演示如何获取客户端的套接字描述符和查看客户端的SSL验证信息。
调用httpd_ssl_start函数即可启动服务器,服务器启动后调用httpd_register_uri_handler函数注册URI服务,这里后面就跟上一篇文章的一样了。
网页的内容就跟之前的一样,在输入框中填写自己的名字,点击“OK”按钮就会跳转到另一个页面。


例程的log有时候会弹出0x7780错误,一般是由于没有设置CA证书导致,客户端或服务器认为对方不安全。
相关文章:
【ESP32】ESP-IDF开发 | WiFi开发 | HTTPS服务器 + 搭建例程
1. 简介 1.1 HTTPS HTTPS(HyperText Transfer Protocol over Secure Socket Layer),全称安全套接字层超文本传输协议,一般理解为HTTPSSL/TLS,通过SSL证书来验证服务器的身份,并为浏览器和服务器之间的通信…...
ollama离线环境部署deepseek及对话网站开发
ollama离线环境部署deepseek及局域网对话网站开发 需要在离线环境下面部署deepseek大模型,而且局域网内用户能在浏览器直接对话,主机的操作系统是win10 经不断探索,找到一条能走通的路,大致流程和思路如下: 局域网服…...
【Unity】 HTFramework框架(六十)Assistant助手(在Unity中接入DeepSeek等AI语言大模型)
更新日期:2025年2月14日。 Github源码:[点我获取源码] Gitee源码:[点我获取源码] 索引 Assistant助手安装Ollama使用Assistant(在编辑器中)打开Assistant配置Assistant使用Assistant处理Assistant回复的内容使用推理大…...
Spring AI集成DeepSeek,实现流式输出
前面一篇文章我们实现了《Spring AI集成DeepSeek:三步搞定Java智能应用》,大模型的响应速度是很慢的,为了提升用户体验,我们通常会使用流式输出一点点将结果输出给用户。先看下效果: 在 SpringBoot 中实现流式输出可以…...
LeetCode 1299.将每个元素替换为右侧最大元素:倒序遍历,维护最大值,原地修改
【LetMeFly】1299.将每个元素替换为右侧最大元素:倒序遍历,维护最大值,原地修改 力扣题目链接:https://leetcode.cn/problems/replace-elements-with-greatest-element-on-right-side/ 给你一个数组 arr ,请你将每个…...
搭建一个经典的LeNet5神经网络
第一章:计算机视觉中图像的基础认知 第二章:计算机视觉:卷积神经网络(CNN)基本概念(一) 第三章:计算机视觉:卷积神经网络(CNN)基本概念(二) 第四章:搭建一个经典的LeNet5神经网络 一、LeNet-5背景 LeNet-…...
我用Ai学Android Jetpack Compose之CircularProgressIndicator
答案来自 通义千问 Q: 我想学习CircularProgressIndicator,麻烦你介绍一下 当然可以!CircularProgressIndicator 是 Jetpack Compose 中的一个组件,用于显示一个循环的圆形进度条。它非常适用于需要指示加载状态或进程完成度的场景。接下来…...
DeepSeek-R1:通过强化学习激励大型语言模型的推理能力
摘要 我们介绍了第一代推理模型DeepSeek-R1-Zero和DeepSeek-R1。DeepSeek-R1-Zero是一个通过大规模强化学习(RL)训练而成的模型,无需监督微调(SFT)作为初步步骤,展示了卓越的推理能力。通过RL,DeepSeek-R1-Zero自然涌现出许多强大而有趣的推理行为。然而,它也面临诸如…...
为什么要选择3D机器视觉检测
选择3D机器视觉检测的原因主要包括以下几点: 高精度测量 复杂几何形状:能够精确测量复杂的三维几何形状。 微小细节:可捕捉微小细节,适用于高精度要求的行业。全面数据获取 深度信息:提供深度信息,弥补2D视…...
Unity 编辑器热更C# FastScriptReload
工具源码:https://github.com/handzlikchris/FastScriptReload 介绍 用于运行时修改C#后能快速重新编译C#并生效,避免每次改C#,unity全部代码重新编译,耗时旧且需要重启游戏。 使用 需要手动调整AssetPipeline自动刷新模式&…...
DeepSeek在linux下的安装部署与应用测试
结合上一篇文章,本篇文章主要讲述在Redhat linux环境下如何部署和使用DeepSeek大模型,主要包括ollama的安装配置、大模型的加载和应用测试。关于Open WebUI在docker的安装部署,Open WebUI官网也提供了完整的docker部署说明,大家可…...
VNC远程控制Mac
前言 macOS系统自带有VNC远程桌面,我们可以在控制端上安装配置VNC客户端,以此来实现远程控制macOS。但通常需要在不同网络下进行远程控制,为此,我们可以在macOS被控端上使用cpolar做内网穿透,映射VNC默认端口5…...
Next.js国际化:next-i18next
引言 next-i18next 是专门为 Next.js 项目量身定制的国际化解决方案,它基于强大的 i18next 库,能帮助开发者轻松地为 Next.js 应用添加多语言支持 next-i18next 初相识 项目简介 next-i18next 是一个专为 Next.js 应用程序打造的国际化解决方案&#…...
计算机视觉:卷积神经网络(CNN)基本概念(一)
第一章:计算机视觉中图像的基础认知 第二章:计算机视觉:卷积神经网络(CNN)基本概念(一) 第三章:计算机视觉:卷积神经网络(CNN)基本概念(二) 第四章:搭建一个经典的LeNet5神经网络 一、引言 卷积神经网络&…...
Python的那些事第二十三篇:Express(Node.js)与 Python:一场跨语言的浪漫邂逅
摘要 在当今的编程世界里,Node.js 和 Python 像是两个性格迥异的超级英雄,一个以速度和灵活性著称,另一个则以强大和优雅闻名。本文将探讨如何通过 Express 框架将 Node.js 和 Python 结合起来,打造出一个高效、有趣的 Web 应用。我们将通过一系列幽默风趣的实例和表格,展…...
核货宝外贸订货系统:批发贸易企业出海的强劲东风
在全球贸易一体化的汹涌浪潮中,批发贸易企业正积极探寻海外市场的广阔天地,试图开辟新的增长版图。然而,出海之路绝非坦途,众多难题如暗礁般潜藏在前行的航道上。从复杂繁琐的跨境交易流程、变幻莫测的国际市场需求,到…...
最新智能优化算法: 阿尔法进化(Alpha Evolution,AE)算法求解23个经典函数测试集,MATLAB代码
一、阿尔法进化算法 阿尔法进化(Alpha Evolution,AE)算法是2024年提出的一种新型进化算法,其核心在于通过自适应基向量和随机步长的设计来更新解,从而提高算法的性能。以下是AE算法的主要步骤和特点: 主…...
数据结构与算法面试专题——堆排序
完全二叉树 完全二叉树中如果每棵子树的最大值都在顶部就是大根堆 完全二叉树中如果每棵子树的最小值都在顶部就是小根堆 设计目标:完全二叉树的设计目标是高效地利用存储空间,同时便于进行层次遍历和数组存储。它的结构使得每个节点的子节点都可以通过简…...
MongoDB索引介绍
索引简述 索引是什么 索引在数据库技术体系中占据了非常重要的位置,其主要表现为一种目录式的数据结构,用来实现快速的数据查询。通常在实现上,索引是对数据库表(集合)中的某些字段进行抽取、排列之后,形成的一种非常易于遍历读取…...
【一文读懂】WebRTC协议
WebRTC(Web Real-Time Communication)协议 WebRTC(Web Real-Time Communication)是一种支持浏览器和移动应用程序之间进行 实时音频、视频和数据通信 的协议。它使得开发者能够在浏览器中实现高质量的 P2P(点对点&…...
【弹性计算】容器、裸金属
容器、裸金属 1.容器和云原生1.1 容器服务1.2 弹性容器实例1.3 函数计算 2.裸金属2.1 弹性裸金属服务器2.2 超级计算集群 1.容器和云原生 容器技术 起源于虚拟化技术,Docker 和虚拟机和谐共存,用户也找到了适合两者的应用场景,二者对比如下图…...
【个人开发】deepspeed+Llama-factory 本地数据多卡Lora微调
文章目录 1.背景2.微调方式2.1 关键环境版本信息2.2 步骤2.2.1 下载llama-factory2.2.2 准备数据集2.2.3 微调模式2.2.3.1 zero-3微调2.2.3.2 zero-2微调2.2.3.3 单卡Lora微调 2.3 踩坑经验2.3.1 问题一:ValueError: Undefined dataset xxxx in dataset_info.json.2…...
两步在 Vite 中配置 Tailwindcss
第一步:安装依赖 npm i -D tailwindcss tailwindcss/vite第二步:引入 tailwindcss 更改配置 // src/main.js import tailwindcss/index// vite.config.js import vue from vitejs/plugin-vue import tailwindcss from tailwindcss/viteexport default …...
使用 HTML CSS 和 JAVASCRIPT 的黑洞动画
使用 HTML CSS 和 JAVASCRIPT 的黑洞动画 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Black Ho…...
计算机视觉-尺度不变区域
一、尺度不变性 1.1 尺度不变性 找到一个函数,实现尺度的选择特性。 1.2 高斯偏导模版求边缘 1.3 高斯二阶导 用二阶过零点检测边缘 高斯二阶导有两个参数:方差和窗宽(给定方差可以算出窗宽) 当图像与二阶导高斯滤波核能匹配…...
SNARKs 和 UTXO链的未来
1. 引言 SNARKs 经常被视为“解决”扩容问题的灵丹妙药。虽然 SNARKs 可以提供令人难以置信的好处,但也需要承认其局限性——SNARKs 无法解决区块链目前面临的现有带宽限制。 本文旨在通过对 SNARKs 对比特币能做什么和不能做什么进行(相对)…...
DeepSeek 通过 API 对接第三方客户端 告别“服务器繁忙”
本文首发于只抄博客,欢迎点击原文链接了解更多内容。 前言 上一期分享了如何在本地部署 DeepSeek R1 模型,但通过命令行运行的本地模型,问答的交互也要使用命令行,体验并不是很好。这期分享几个第三方客户端,涵盖了桌…...
性格测评小程序07用户登录
目录 1 创建登录页2 在首页检查登录状态3 搭建登录功能最终效果总结 小程序注册功能开发好了之后,就需要考虑登录的问题。首先要考虑谁作为首页,如果把登录页作为首页,比较简单,每次访问的时候都需要登录。 如果把功能页作为首页&…...
红队视角出发的k8s敏感信息收集——日志与监控系统
针对 Kubernetes 日志与监控系统 的详细攻击视角分析,聚焦 集群审计日志 和 Prometheus/Grafana 暴露 的潜在风险及利用方法 攻击链示例 1. 攻击者通过容器逃逸进入 Pod → 2. 发现未认证的 Prometheus 服务 → 3. 查询环境变量标签获取数据库密码 → 4. 通过审…...
deepseek多列数据对比,联想到excel的高级筛选功能
目录 1 业务背景 2 deepseek提示词输入 3 联想分析 4 EXCEL高级搜索 1 业务背景 系统上线的时候经常会遇到一个问题,系统导入的数据和线下的EXCEL数据是否一致,如果不一致,如何快速找到差异值,原来脑海第一反应就是使用公…...
