SOC-ESP32S3部分:25-HTTP请求

article/2025/6/28 10:46:12

飞书文档https://x509p6c8to.feishu.cn/wiki/KL4RwxUQdipzCSkpB2lcBd03nvK

HTTP(Hyper Text Transfer Protocol) 超文本传输协议,是一种建立在 TCP 上的无状态连接,整个基本的工作流程是客户端发送一个 HTTP 请求,说明客户端想要访问的资源和请求的动作,服务端收到请求之后,服务端开始处理请求,并根据请求做出相应的动作访问服务器资源,最后通过发送 HTTP 响应把结果返回给客户端。

HTTP请求方法:

一般有 GET、POST、PUT、DELETE,含义分别是获取、修改、上传、删除.

其中 GET 方式仅仅为获取服务器资源,方式较为简单,因此在请求方式为 GET 的 HTTP 请求数据中,请求正文部分可以省略,直接将想要获取的资源添加到 URL 中。

请求头:包括一些访问的域名、用户代理、Cookie等信息。

请求正文:就是HTTP请求的数据。

如下发,就是一个简单的HTTP请求示例,在执行HTTP请求前,设备必须先进行配网,配网使用的是我们上节课讲解的代码。

HTTP部分核心逻辑如下,设备配网成功后,设置全局变量is_connect_wifi为true,然后执行http_get_request发送一次GET请求,请求发送给http://www.example.com/服务器。

主要流程如下:

  1. 配置http请求参数和回调处理函数
  2. 初始化http客户端
  3. 执行http请求,监听回调
  4. 清理HTTP客户端资源,释放句柄。

配置http请求参数和回调处理函数

esp_http_client_config_t
描述: 配置ESP32 HTTP客户端的参数。
字段:
.method: HTTP请求方法,例如 HTTP_METHOD_GET 表示GET请求。
.url: 请求的目标URL。
.event_handler: 自定义事件处理函数,用于处理HTTP请求过程中的事件。
.user_data: 用户自定义数据,可以传递给事件处理函数或存储响应数据。_http_event_handler
描述: 自定义的HTTP事件处理函数。
用途: 处理HTTP请求过程中发生的事件(如连接建立、数据接收等)。
注意: 代码中未提供具体实现,但通常需要根据事件类型执行相应的逻辑。使用示例:char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};esp_http_client_config_t config = {.method = HTTP_METHOD_GET,           //get请求.url = "http://www.example.com/",     //请求url.event_handler = _http_event_handler,.user_data = local_response_buffer,        // Pass address of local buffer to get response};_http_event_handler为http请求后的回调函数:
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{switch(evt->event_id) {case HTTP_EVENT_ERROR:    //错误事件ESP_LOGI(TAG, "HTTP_EVENT_ERROR");break;case HTTP_EVENT_ON_CONNECTED:    //连接成功事件ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");break;case HTTP_EVENT_HEADER_SENT:    //发送头事件ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");break;case HTTP_EVENT_ON_HEADER:    //接收头事件ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER");break;case HTTP_EVENT_ON_DATA:    //接收数据事件ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);break;case HTTP_EVENT_ON_FINISH:    //会话完成事件ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");break;case HTTP_EVENT_DISCONNECTED:    //断开事件ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");break;case HTTP_EVENT_REDIRECT:break;}return ESP_OK;
}

初始化http客户端

esp_http_client_init
esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *config);
功能: 初始化HTTP客户端并返回句柄。
参数:
config: 指向esp_http_client_config_t结构体的指针,包含HTTP客户端的配置信息。
返回值: 返回HTTP客户端的句柄。

执行http请求

esp_err_t esp_http_client_perform(esp_http_client_handle_t client);
功能: 执行HTTP请求并等待响应。
参数:
client: HTTP客户端句柄。
返回值:
ESP_OK: 请求成功。
其他错误码: 请求失败。

清理HTTP客户端资源,释放句柄。

void esp_http_client_cleanup(esp_http_client_handle_t client);
功能: 清理HTTP客户端资源,释放句柄。
参数:
client: HTTP客户端句柄。

最终代码如下:

#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_eap_client.h"
#include "esp_netif.h"
#include "esp_smartconfig.h"
#include "esp_mac.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"#include "esp_http_client.h"static const char *TAG = "http_client";static EventGroupHandle_t s_wifi_event_group;static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static void smartconfig_example_task(void *parm);
static bool is_connect_wifi = false;#define MAX_HTTP_OUTPUT_BUFFER 2048esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{switch(evt->event_id) {case HTTP_EVENT_ERROR:    //错误事件ESP_LOGI(TAG, "HTTP_EVENT_ERROR");break;case HTTP_EVENT_ON_CONNECTED:    //连接成功事件ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");break;case HTTP_EVENT_HEADER_SENT:    //发送头事件ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");break;case HTTP_EVENT_ON_HEADER:    //接收头事件ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER");printf("%.*s", evt->data_len, (char*)evt->data);break;case HTTP_EVENT_ON_DATA:    //接收数据事件ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);if (!esp_http_client_is_chunked_response(evt->client)) {printf("%.*s", evt->data_len, (char*)evt->data);}break;case HTTP_EVENT_ON_FINISH:    //会话完成事件ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");break;case HTTP_EVENT_DISCONNECTED:    //断开事件ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");break;case HTTP_EVENT_REDIRECT:break;}return ESP_OK;
}static void http_get_request(){char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};esp_http_client_config_t config = {.method = HTTP_METHOD_GET,           //get请求.url = "http://www.example.com/",     //请求url.event_handler = _http_event_handler,.user_data = local_response_buffer,        // Pass address of local buffer to get response};esp_http_client_handle_t client = esp_http_client_init(&config);// GETesp_err_t err = esp_http_client_perform(client);if (err == ESP_OK) {ESP_LOGI(TAG, "HTTP GET OK");} else {ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));}ESP_LOGI(TAG, "%s\n", local_response_buffer);   esp_http_client_cleanup(client);
}static void http_get_task(void *pvParameters)
{while (1){if (is_connect_wifi){http_get_request();}vTaskDelay(8000 / portTICK_PERIOD_MS);}
}static void event_handler(void *arg, esp_event_base_t event_base,int32_t event_id, void *event_data)
{if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START){// WiFi 站点模式启动后,创建 SmartConfig 任务xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);}else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED){is_connect_wifi = false;// WiFi 断开连接时,重新连接并清除连接标志位esp_wifi_connect();xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);}else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP){// 获取到 IP 地址后,设置连接标志位xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);is_connect_wifi = true;}else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE){// SmartConfig 扫描完成事件ESP_LOGI(TAG, "Scan done");}else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL){// SmartConfig 找到信道事件ESP_LOGI(TAG, "Found channel");}else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD){// SmartConfig 获取到 SSID 和密码事件ESP_LOGI(TAG, "Got SSID and password");smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;wifi_config_t wifi_config;uint8_t ssid[33] = {0};uint8_t password[65] = {0};uint8_t rvd_data[33] = {0};bzero(&wifi_config, sizeof(wifi_config_t));memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));memcpy(ssid, evt->ssid, sizeof(evt->ssid));memcpy(password, evt->password, sizeof(evt->password));ESP_LOGI(TAG, "SSID:%s", ssid);ESP_LOGI(TAG, "PASSWORD:%s", password);if (evt->type == SC_TYPE_ESPTOUCH_V2){// 如果使用的是 ESPTouch V2,获取额外的数据ESP_ERROR_CHECK(esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)));ESP_LOGI(TAG, "RVD_DATA:");for (int i = 0; i < 33; i++){printf("%02x ", rvd_data[i]);}printf("\n");}// 断开当前 WiFi 连接,设置新的 WiFi 配置并重新连接ESP_ERROR_CHECK(esp_wifi_disconnect());ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));esp_wifi_connect();}else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE){// SmartConfig 发送 ACK 完成事件,设置 SmartConfig 完成标志位xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);}
}static void smartconfig_example_task(void *parm)
{EventBits_t uxBits;wifi_config_t myconfig = {0};ESP_LOGI(TAG, "creat smartconfig_example_task");// 获取wifi配置信息esp_wifi_get_config(ESP_IF_WIFI_STA, &myconfig);if (strlen((char *)myconfig.sta.ssid) > 0){// 如果配置过,就直接连接wifiESP_LOGI(TAG, "alrealy set, SSID is :%s,start connect", myconfig.sta.ssid);esp_wifi_connect();}else{// 如果没有配置过,就进行配网操作ESP_LOGI(TAG, "have no set, start to config");ESP_ERROR_CHECK(esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS)); // 支持APP ESPTOUCH和微信AIRKISSsmartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_smartconfig_start(&cfg));}while (1){// 等待连接标志位或 SmartConfig 完成标志位uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);if (uxBits & CONNECTED_BIT){// 连接到 AP 后的日志ESP_LOGI(TAG, "WiFi Connected to ap");// 联网成功后,可以关闭线程vTaskDelete(NULL);}if (uxBits & ESPTOUCH_DONE_BIT){// SmartConfig 完成后的日志ESP_LOGI(TAG, "smartconfig over");// 停止 SmartConfigesp_smartconfig_stop();// 删除 SmartConfig 任务vTaskDelete(NULL);}}
}void app_main(void)
{// 初始化 NVS 闪存ESP_ERROR_CHECK( nvs_flash_init());// 初始化网络接口ESP_ERROR_CHECK(esp_netif_init());// 创建事件组s_wifi_event_group = xEventGroupCreate();// 创建默认事件循环ESP_ERROR_CHECK(esp_event_loop_create_default());// 创建默认的 WiFi 站点模式网络接口esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();assert(sta_netif);// 初始化 WiFi 配置wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));// 注册事件处理函数ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));ESP_ERROR_CHECK(esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));// 设置 WiFi 模式为站点模式并启动 WiFiESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));ESP_ERROR_CHECK(esp_wifi_start());xTaskCreate(&http_get_task, "http_get_task", 9192, NULL, 5, NULL);
}

对于POST请求

只需要把esp_http_client_config_t的method设置为HTTP_METHOD_POST,另外安装服务器的参数,填写esp_http_client_set_header和esp_http_client_set_post_field即可。例如,我们需要发送JSON数据包{"field1":"value1"}给服务器http://httpbin.org/post,具体POST请求实现如下:

static void http_post(void)
{esp_http_client_config_t config = {.method = HTTP_METHOD_POST,        .url = "http://httpbin.org/post",    .event_handler = _http_event_handler,};esp_http_client_handle_t client = esp_http_client_init(&config);// POSTconst char *post_data = "{\"field1\":\"value1\"}";esp_http_client_set_header(client, "Content-Type", "application/json");esp_http_client_set_post_field(client, post_data, strlen(post_data));esp_err_t err = esp_http_client_perform(client);if (err == ESP_OK) {ESP_LOGI(TAG, "HTTP POST OK");} else {ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));}esp_http_client_cleanup(client);
}

对于HTTPS请求

只需额外配置esp_http_client_config_t 的url为https连接,另外添加证书文件即可cert_pem,例如

    esp_http_client_config_t config = {.method = HTTP_METHOD_GET,.url = "https://www.howsmyssl.com/",.event_handler = _http_event_handler,.cert_pem = howsmyssl_com_root_cert_pem_start,};

esp_http_client_config_t更多参数说明如下:可按需使用

typedef struct {const char                  *url;/*!< HTTP URL,URL 信息是最重要的,如果设置了此参数,它将覆盖下面的其他字段(如果有的话) */const char                  *host;/*!< 以字符串形式表示的域名或 IP 地址 */int                         port;/*!< 要连接的端口,默认值取决于 esp_http_client_transport_t(80 用于 HTTP,443 用于 HTTPS) */const char                  *username;/*!< 用于 HTTP 认证 */const char                  *password;/*!< 用于 HTTP 认证 */esp_http_client_auth_type_t auth_type;/*!< HTTP 认证类型,请参阅 `esp_http_client_auth_type_t` */const char                  *path;/*!< HTTP 路径,如果未设置,默认值为 `/` */const char                  *query;/*!< HTTP 查询字符串 */const char                  *cert_pem;/*!< SSL 服务器证书,以 PEM 格式表示的字符串,如果客户端需要验证服务器 */size_t                      cert_len;/*!< 指向 cert_pem 的缓冲区长度。如果是 null 结尾的 PEM 字符串,可为 0 */const char                  *client_cert_pem;/*!< SSL 客户端证书,以 PEM 格式表示的字符串,如果服务器需要验证客户端 */size_t                      client_cert_len;/*!< 指向 client_cert_pem 的缓冲区长度。如果是 null 结尾的 PEM 字符串,可为 0 */const char                  *client_key_pem;/*!< SSL 客户端密钥,以 PEM 格式表示的字符串,如果服务器需要验证客户端 */size_t                      client_key_len;/*!< 指向 client_key_pem 的缓冲区长度。如果是 null 结尾的 PEM 字符串,可为 0 */const char                  *client_key_password;/*!< 客户端密钥解密密码字符串 */size_t                      client_key_password_len;/*!< 指向 client_key_password 的密码字符串长度 */esp_http_client_proto_ver_t tls_version;/*!< 连接的 TLS 协议版本,例如,TLS 1.2、TLS 1.3(默认 - 无偏好) */
#ifdef CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGNbool                        use_ecdsa_peripheral;/*!< 使用 ECDSA 外设来使用私钥 */uint8_t                     ecdsa_key_efuse_blk;/*!< ECDSA 密钥存储的 efuse 块 */
#endifconst char                  *user_agent;/*!< 随 HTTP 请求发送的用户代理字符串 */esp_http_client_method_t    method;/*!< HTTP 请求方法 */int                         timeout_ms;/*!< 网络超时时间,单位为毫秒 */bool                        disable_auto_redirect;/*!< 禁用 HTTP 自动重定向 */int                         max_redirection_count;/*!< 收到 HTTP 重定向状态码时的最大重定向次数,如果为 0,则使用默认值 */int                         max_authorization_retries;/*!< 收到 HTTP 未授权状态码时的最大连接重试次数,如果为 0,则使用默认值。如果为 -1,则禁用授权重试 */http_event_handle_cb        event_handler;/*!< HTTP 事件处理函数 */esp_http_client_transport_t transport_type;/*!< HTTP 传输类型,请参阅 `esp_http_client_transport_t` */int                         buffer_size;/*!< HTTP 接收缓冲区大小 */int                         buffer_size_tx;/*!< HTTP 发送缓冲区大小 */void                        *user_data;/*!< HTTP 用户数据上下文 */bool                        is_async;/*!< 设置异步模式,目前仅支持 HTTPS */bool                        use_global_ca_store;/*!< 对所有设置了此布尔值的连接使用全局 CA 证书存储 */bool                        skip_cert_common_name_check;/*!< 跳过对服务器证书 CN 字段的任何验证 */const char                  *common_name;/*!< 指向包含服务器证书通用名称的字符串指针。如果不为 NULL,服务器证书的 CN 必须与此名称匹配;如果为 NULL,服务器证书的 CN 必须与主机名匹配。 */esp_err_t (*crt_bundle_attach)(void *conf);/*!< 指向 esp_crt_bundle_attach 的函数指针。启用使用证书包进行服务器验证,必须在菜单配置中启用 */bool                        keep_alive_enable;/*!< 启用 keep-alive 超时机制 */int                         keep_alive_idle;/*!< keep-alive 空闲时间。默认值为 5(秒) */int                         keep_alive_interval;/*!< keep-alive 间隔时间。默认值为 5(秒) */int                         keep_alive_count;/*!< keep-alive 数据包重试发送次数。默认值为 3 次 */struct ifreq                *if_name;/*!< 数据要通过的接口名称。如果未设置,则使用默认接口 */
#if CONFIG_ESP_TLS_USE_SECURE_ELEMENTbool use_secure_element;/*!< 启用此选项以使用安全元件 */
#endif
#if CONFIG_ESP_TLS_USE_DS_PERIPHERALvoid *ds_data;/*!< 数字签名外设上下文指针,更多详细信息请参阅 ESP - TLS 文档 */
#endif
#if CONFIG_ESP_TLS_CLIENT_SESSION_TICKETSbool save_client_session;
#endif
#if CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORTstruct esp_transport_item_t *transport;
#endif
} esp_http_client_config_t;

HTTPS请求需要做服务器证书校验,所以需要添加证书,证书是由服务器提供的,这里用到两个服务器进行测试,所以需要用到两个证书,拷贝idf证书到工程main下方

esp-idf/examples/protocols/esp_http_client/main/howsmyssl_com_root_cert.pem

esp-idf/examples/protocols/esp_http_client/main/postman_root_cert.pem

拷贝证书到工程路径后,还需要添加到CMakeLists.txt中,保证烧录到设备中

demo/main/CMakeLists.txt

idf_component_register(SRCS "main.c"INCLUDE_DIRS "."EMBED_TXTFILES howsmyssl_com_root_cert.pem postman_root_cert.pem)

最后请求代码如下:

//howsmyssl服务器证书位置
extern const char howsmyssl_com_root_cert_pem_start[] asm("_binary_howsmyssl_com_root_cert_pem_start");
extern const char howsmyssl_com_root_cert_pem_end[]   asm("_binary_howsmyssl_com_root_cert_pem_end");
//postman服务器证书位置
extern const char postman_root_cert_pem_start[] asm("_binary_postman_root_cert_pem_start");
extern const char postman_root_cert_pem_end[]   asm("_binary_postman_root_cert_pem_end");static void https_get_request(void)
{esp_http_client_config_t config = {.method = HTTP_METHOD_GET,.url = "https://www.howsmyssl.com/",.event_handler = _http_event_handler,.cert_pem = howsmyssl_com_root_cert_pem_start,};esp_http_client_handle_t client = esp_http_client_init(&config);esp_err_t err = esp_http_client_perform(client);if (err == ESP_OK) {ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %"PRId64,esp_http_client_get_status_code(client),esp_http_client_get_content_length(client));} else {ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));}esp_http_client_cleanup(client);
}static void https_post(){esp_http_client_config_t config = {.method = HTTP_METHOD_POST,.url = "https://www.postman-echo.com/post",.event_handler = _http_event_handler,.cert_pem = postman_root_cert_pem_start,.is_async = true,.timeout_ms = 5000,};esp_http_client_handle_t client = esp_http_client_init(&config);esp_err_t err;const char *post_data = "this is xiaozhi post data";esp_http_client_set_post_field(client, post_data, strlen(post_data));while (1) {err = esp_http_client_perform(client);if (err != ESP_ERR_HTTP_EAGAIN) {break;}}if (err == ESP_OK) {ESP_LOGI(TAG, "HTTPS Status = %d, content_length = %"PRId64,esp_http_client_get_status_code(client),esp_http_client_get_content_length(client));} else {ESP_LOGE(TAG, "Error perform http request %s", esp_err_to_name(err));}esp_http_client_cleanup(client);
}

这个实验需要先完成WiFi配网哦,具体看WiFi章节24-WiFi配网


http://www.hkcw.cn/article/cCwWfvjUgV.shtml

相关文章

【音视频】H265 NALU分析

1 H265 概述 H264 与 H265 的区别 传输码率&#xff1a;H264 由于算法优化&#xff0c;可以低于 2Mbps 的速度实现标清数字图像传送&#xff1b;H.265 High Profile 可实现低于 1.5Mbps 的传输带宽下&#xff0c;实现 1080p 全高清视频传输。 编码架构&#xff1a;H.265/HEVC…

第十二节:第四部分:集合框架:List系列集合:LinkedList集合的底层原理、特有方法、栈、队列

LinkedList集合的底层原理 LinkedList集合的应用场景之一 代码&#xff1a;掌握LinkedList集合的使用 package com.itheima.day19_Collection_List;import java.util.LinkedList; import java.util.List;//掌握LinkedList集合的使用。 public class ListTest3 {public static …

用 Whisper 打破沉默:AI 语音技术如何重塑无障碍沟通方式?

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

实现Cursor + Pycharm 交互

效果演示&#xff1a; 直接可以在cursor或Pycharm中点击右键点击&#xff0c;然后就可以跳转到另一个应用的对应位置了 使用方法&#xff1a; 分别在两个应用中安装插件【Switch2Cursor Switch2IDEA&#xff0c;这两个插件分别安装在 IDEA 和 Cursor 中】&#xff1a; Switc…

【Linux】进程控制-上

> &#x1f343; 本系列为Linux的内容&#xff0c;如果感兴趣&#xff0c;欢迎订阅&#x1f6a9; > &#x1f38a;个人主页:【小编的个人主页】 >小编将在这里分享学习Linux的心路历程✨和知识分享&#x1f50d; >如果本篇文章有不足&#xff0c;还请多多包涵&a…

QT之头像剪裁效果实现

文章目录 源码地址&#xff0c;环境&#xff1a;QT5.15&#xff0c;MinGW32位效果演示导入图片设置剪裁区域创建剪裁小窗口重写剪裁小窗口的鼠标事件mousePressEventmouseMoveEventmouseReleaseEvent 小窗口移动触发父窗口的重绘事件剪裁效果实现 源码地址&#xff0c;环境&…

Android基于LiquidFun引擎实现软体碰撞效果

一、实现效果 Android使用LiquidFun物理引擎实现果冻碰撞效果 二、Android代码 // 加载liquidfun动态库static {System.loadLibrary("liquidfun");System.loadLibrary("liquidfun_jni");}class ParticleData {long id;ParticleSystem particleSystem;float…

Baklib赋能企业AI知识管理实践

Baklib构建AI-ready知识体系 Baklib作为新一代知识中台的核心引擎&#xff0c;通过知识图谱构建与自然语言处理&#xff08;NLP&#xff09;技术&#xff0c;将碎片化信息转化为结构化知识资产。平台依托智能语义分析能力&#xff0c;自动识别文档中的实体关系与上下文逻辑&am…

如何在 Windows 11 24H2 的任务栏时钟中显示秒数

我们都很熟悉任务栏时钟&#xff0c;或者说&#xff0c;是我们运行 Windows 的电脑屏幕右下角的数字时钟。它显示小时和分钟的时间&#xff0c;这基本上是每个人需要的&#xff0c;但我们有时也需要看到秒数。随着 Windows 11 的最新更新&#xff0c;它可以在任务栏时钟中直接显…

navicate菜单栏不见了怎么办

别慌&#xff01;&#xff01;&#xff01; 将鼠标放到navicate框的最左侧&#xff0c;看到出现两个竖线&#xff08;像这样||&#xff09;&#xff0c;点击拖动鼠标拉出来吧。

张家界溶洞垃圾堆7层楼高 污染触目惊心

近日,一段视频曝光了张家界市慈利县一处天然溶洞遭到人为排污的情况,引发广泛关注。视频中,溶洞内流淌着泛着绿色的污水,伴有黄绿色的淤泥沉积,黑色污染物自洞壁滑落凝固成厚厚的“黑痂”。拍摄者称,垃圾堆积高度达到七八层楼,令人触目惊心。据张家界市生态环境局透露,…

软件安全保障关键之漏洞扫描:原理、分类及意义全解析?

软件安全保障的关键在于漏洞扫描&#xff0c;这项工作通过特定技术和流程进行&#xff0c;旨在发现软件中可能存在的安全隐患&#xff0c;比如缓冲区溢出、跨站脚本攻击等&#xff0c;这些漏洞得以被识别和记录&#xff0c;对确保软件安全具有重要意义。 扫描原理 漏洞扫描依…

韩国大选开始投票 5人竞逐总统 李在明领跑民调

韩国第21届总统大选于当地时间6月3日6时正式开始,全国共设有14295个投票站。没有参加提前投票的选民凭身份证件前往指定投票站即可参与投票,投票将于当日20时结束。本次大选共有7位候选人登记,但其中两位宣布退出并支持国民力量党候选人金文洙。因此,选民将从以下5位候选人…

计算机网络 : 应用层自定义协议与序列化

计算机网络 &#xff1a; 应用层自定义协议与序列化 目录 计算机网络 &#xff1a; 应用层自定义协议与序列化引言1. 应用层协议1.1 再谈协议1.2 网络版计算器1.3 序列化与反序列化 2. 重新理解全双工3. socket和协议的封装4. 关于流失数据的处理5. Jsoncpp5.1 特性5.2 安装5.3…

比亚迪打响降价战为哪般 应对销量与利润双重压力

比亚迪打响降价战为哪般 应对销量与利润双重压力。5月22日,比亚迪宣布对旗下王朝网和海洋网共计22款车型降价,降幅在1.2万元至5.3万元之间,活动将持续到6月底。这是比亚迪自三月底以来的第三次降价,力度最大。作为中国新能源汽车销量冠军,比亚迪的大面积、大幅度降价预示着…

电子电器架构 --- 远程信息控制单元(TCU)

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所谓鸡汤&#xff0c;要么蛊惑你认命&#xff0c;要么怂恿你拼命&#xff0c;但都是回避问题的根源&…

榴莲大降价!它能从“奢侈果”变成“亲民果”吗

夏季是各类水果集中上市的季节,榴莲爱好者们最近有口福了,市场上榴莲价格出现了大幅下降,甚至“腰斩”的情况。造成榴莲价格下跌的原因都有哪些?榴莲会不会就此从“奢侈果”变成“亲民果”?走进位于浙江湖州的一家榴莲批发店,榴莲成堆地被摆放在货架上,老板肖女士正在开…

ULVAC A2K 20K 40K CU Bar type 主动灭弧器 Active Arc Killer

ULVAC A2K 20K 40K CU Bar type 主动灭弧器 Active Arc Killer

美国再提高进口钢铝关税有何目的 贸易保护主义抬头

美国再提高进口钢铝关税有何目的 贸易保护主义抬头。当地时间5月30日,美国总统特朗普在宾夕法尼亚州的一场集会上宣布,将把进口钢铁的关税从25%提高至50%,并表示该决定从6月4日起生效。白宫当天也在社交媒体上发布公告称,为进一步保护美国钢铁行业免受外国和不公平竞争的影…

PCIe 边缘卡的 PCB 设计和引脚排列

标准台式计算机和嵌入式计算机中最常见的附加卡是 PCIe 卡。PCIe 附加卡具有多种外形尺寸&#xff0c;并使用边缘插槽连接器&#xff0c;可沿主板垂直或直角安装。您还有不同类型的 PCIe 设备&#xff0c;例如插入 M.2 连接器的 SSD 或模块。 在本文中&#xff0c;我将介绍使用…