Hi3861 OpenHarmony嵌入式應用入門--MQTT

MQTT 是機器對機器(M2M)/物聯網(IoT)連接協議。它被設計為一個極其輕量級的發布/訂閱消息傳輸 協議。對于需要較小代碼占用空間和/或網絡帶寬非常寶貴的遠程連接非常有用,是專為受限設備和低帶寬、 高延遲或不可靠的網絡而設計。這些原則也使該協議成為新興的“機器到機器”(M2M)或物聯網(IoT)世界 的連接設備,以及帶寬和電池功率非常高的移動應用的理想選擇。例如,它已被用于通過衛星鏈路與代理 通信的傳感器、與醫療服務提供者的撥號連接,以及一系列家庭自動化和小型設備場景。它也是移動應用 的理想選擇,因為它體積小,功耗低,數據包最小,并且可以有效地將信息分配給一個或多個接收器。M QTT 通信模型如下圖所示:

前提需要在電腦上運行起來mqtt的服務器,emqx軟件非常合適,他還帶了mqtt的客戶端,很方便調試,具體下載和安裝方法見下面博文,也可以去emqx官網下載最新版進行免費試用。

MQTT:windows最簡單搭建mqtt服務端及本地客戶端測試_emqx-windows-4.3.6-CSDN博客

修改網絡參數

在Hi3861開發板上運行上述四個測試程序之前,需要根據你的無線路由、Linux系統IP修改 net_params.h文件的相關代碼:

  • PARAM_HOTSPOT_SSID 修改為你的熱點名稱
  • PARAM_HOTSPOT_PSK 修改為你的熱點密碼;
  • PARAM_SERVER_ADDR 修改為你的服務器IP地址;
  • PARAM_SERVER_PORT 修改為你的服務器端口號;
  • SERVER_IP_ADDR 修改為你的mqtt服務器IP地址;
  • SERVER_IP_PORT 修改為mqtt的tcp端口,默認為1883;
  • MQTT_TOPIC_SUB 訂閱ID;
  • MQTT_TOPIC_PUB 發布的ID;
  • MQTT_CLIENT_ID MQTT的客戶端ID;
  • MQTT_USER_NAME MQTT的用戶名;
  • MQTT_PASSWORD MQTT的密碼;

代碼編寫

修改D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\BUILD.gn文件

# Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#    http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License. import("//build/lite/config/component/lite_component.gni")lite_component("demo") {features = [#"base_00_helloworld:base_helloworld_example",#"base_01_led:base_led_example",#"base_02_loopkey:base_loopkey_example",#"base_03_irqkey:base_irqkey_example",#"base_04_adc:base_adc_example",#"base_05_pwm:base_pwm_example",#"base_06_ssd1306:base_ssd1306_example",#"kernel_01_task:kernel_task_example",#"kernel_02_timer:kernel_timer_example",#"kernel_03_event:kernel_event_example",#"kernel_04_mutex:kernel_mutex_example",#"kernel_05_semaphore_as_mutex:kernel_semaphore_as_mutex_example",#"kernel_06_semaphore_for_sync:kernel_semaphore_for_sync_example",#"kernel_07_semaphore_for_count:kernel_semaphore_for_count_example",#"kernel_08_message_queue:kernel_message_queue_example",#"wifi_09_hotspot:wifi_hotspot_example",#"wifi_10_sta:wifi_sta_example",#"tcp_11_server:tcp_server_example",#"tcp_12_client:tcp_client_example",#"udp_13_server:udp_server_example",#"udp_14_client:udp_client_example","network_15_mqtt:network_mqtt_example",]
}

創建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\network_15_mqtt文件夾

文件夾中創建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\network_15_mqtt\BUILD.gn文件

# Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#    http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License. static_library("network_mqtt_example") {sources = ["network_mqtt_example.c","network_mqtt.c","wifi_connecter.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTConnectClient.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTConnectServer.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTDeserializePublish.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTFormat.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTPacket.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTSerializePublish.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTSubscribeClient.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTSubscribeServer.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTUnsubscribeServer.c","//third_party/paho.mqtt.embedded-c/MQTTPacket/src/MQTTUnsubscribeClient.c",]include_dirs = ["//utils/native/lite/include","//kernel/liteos_m/kal/cmsis","//base/iot_hardware/peripheral/interfaces/kits","//foundation/communication/wifi_lite/interfaces/wifiservice","//vendor/hqyj/fs_hi3861/common/bsp/include","//third_party/paho.mqtt.embedded-c/MQTTPacket/src","//third_party/cJSON",]
}

文件夾中創建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\network_15_mqtt\network_mqtt.h文件,文件主要包含mqtt的函數。

/** Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**    http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#ifndef NETWORK_MQTT_H
#define NETWORK_MQTT_H/*** @brief MQTT  連接MQTT服務器* @return Returns {0} 成功;*         Returns {-1} 失敗.*/
int MQTTClient_connectServer(const char *ip_addr, int ip_port);
/*** @brief MQTT  斷開連接MQTT服務器* @return Returns {0} 成功;*         Returns {-1} 失敗.*/
int MQTTClient_unConnectServer(void);
/*** @brief MQTT  訂閱MQTT主題* @return Returns {0} 成功;*         Returns {-1} 失敗.*/
int MQTTClient_subscribe(char *subTopic);
/*** @brief MQTT 客戶端的初始化* @param clientID  客戶端ID* @param userName  用戶名* @param password  密碼* @return Returns {0} 成功;*         Returns {-1} 失敗.*/
int MQTTClient_init(char *clientID, char *userName, char *password);
/*** @brief MQTT 發布消息* @param pub_Topic 具有發布權限的主題名稱* @param payloadData  發布數據* @param payloadLen 發布數據的長度* @return Returns {0} 成功;*         Returns {-1} 失敗.*/
int MQTTClient_pub(char *pub_Topic, unsigned char *payloadData, int payloadLen);
/*** @brief MQTT  接收消息* @param callback 當接收到消息之后,將消息傳到到回調函數中* @return Returns {0} 成功;*         Returns {-1} 失敗.*/
int MQTTClient_sub(void);extern int8_t(*p_MQTTClient_sub_callback)(unsigned char *topic, unsigned char *payload);#endif // !NETWORK_MQTT_H

文件夾中創建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\network_15_mqtt\network_mqtt.c文件,文件主要包含mqtt的函數實現。

/** Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**    http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "lwip/netifapi.h"
#include "lwip/sockets.h"
#include "wifi_device.h"
#include "ohos_init.h"
#include "MQTTPacket.h"
#include "network_mqtt.h"#define MQTT_BUFF_MAX_SIZE 512int g_tcp_socket_fd = 0; // 網絡套接字
unsigned char mqttBuff[MQTT_BUFF_MAX_SIZE] = {0};// 發送網絡數據
static int transport_sendPacketBuffer(unsigned char *buf, int buflen)
{int rc = send(g_tcp_socket_fd, buf, buflen, 0);return (rc <= 0) ? 0 : 1;
}
// 接收網絡數據
static int transport_getdata(unsigned char *buf, int count)
{int rc = recv(g_tcp_socket_fd, buf, count, 0);return rc;
}// 連接服務器
int MQTTClient_connectServer(const char *ip_addr, int ip_port)
{if (ip_addr == NULL) {return -1;}int res = 0;                        // 函數返回值struct sockaddr_in tcpServerConfig; // tcp服務器信息// 創建TCP套接字g_tcp_socket_fd = socket(AF_INET, SOCK_STREAM, 0);if (g_tcp_socket_fd < 0) {printf("Failed to create Socket\r\n");}// 連接TCP服務器tcpServerConfig.sin_family = AF_INET;                 // IPV4tcpServerConfig.sin_port = htons(ip_port);            // 填寫服務器的IP端口號tcpServerConfig.sin_addr.s_addr = inet_addr(ip_addr); // 填寫服務器的IP地址res = connect(g_tcp_socket_fd, (struct sockaddr *)&tcpServerConfig, sizeof(tcpServerConfig)); // 連接服務器if (res == -1) {printf("Failed to connect to the server\r\n");return -1;}printf("Connection to server successful\r\n");return 0;
}// 斷開TCP服務器 0:成功, -1:失敗
int MQTTClient_unConnectServer(void)
{int ret = 0;printf("Server shut down successfully\r\n");ret = close(g_tcp_socket_fd);g_tcp_socket_fd = 0;return ret;
}// mqtt客戶端 訂閱主題
int MQTTClient_subscribe(char *subTopic)
{if (subTopic == NULL) {printf("Incorrect parameters\r\n");return -1;}int len = 0, res = 0;int subcount = 0, granted_qos = 0, req_qos = 0;unsigned short submsgid = 0;MQTTString topicString = MQTTString_initializer;/* subscribe */topicString.cstring = subTopic;len = MQTTSerialize_subscribe(mqttBuff, sizeof(mqttBuff), 0, 1, 1, &topicString, &req_qos);if (len <= 0) {printf("MQTTSerialize_subscribe Error %d\r\n", len);return -1;}res = transport_sendPacketBuffer(mqttBuff, len);if (res != 1) {printf("transport_sendPacketBuffer Error %d\r\n", res);return -1;}sleep(1);memset_s(mqttBuff, sizeof(mqttBuff), 0, sizeof(mqttBuff));/* wait for suback */if (MQTTPacket_read(mqttBuff, sizeof(mqttBuff), transport_getdata) != SUBACK) {printf("MQTTPacket_read Error\r\n");return -1;}if (MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, mqttBuff, sizeof(mqttBuff)) != 1) {printf("MQTTDeserialize_suback Error\r\n");return -1;}printf("MQTT subscribed to topics successfully\r\n");return 0;
}// 保持在線時長 60s
#define MQTT_KEEP_ALIVE 60
#define MQTT_DELAY_TIME 3// mqtt客戶端 初始化
int MQTTClient_init(char *clientID, char *userName, char *password)
{if (clientID == NULL || userName == NULL || password == NULL) {printf("Incorrect parameters\r\n");return -1;}int res = 0, len = 0, i = 0;int mqtt_read_len = 10;unsigned char sessionPresent = 0, connack_rc = 0;MQTTPacket_connectData mqttData = MQTTPacket_connectData_initializer;// 初始化MQTT客戶端mqttData.clientID.cstring = clientID;mqttData.username.cstring = userName;mqttData.password.cstring = password;mqttData.cleansession = true;  // 是否初始化的時候,清除上一次的對話mqttData.keepAliveInterval = MQTT_KEEP_ALIVE;// 組MQTT消息包len = MQTTSerialize_connect(mqttBuff, sizeof(mqttBuff), &mqttData);if (len <= 0) {printf("MQTTSerialize_connect Error %d\r\n", res);return -1;}res = transport_sendPacketBuffer(mqttBuff, len);if (res != 1) {printf("transport_sendPacketBuffer Error %d\r\n", res);return -1;}sleep(MQTT_DELAY_TIME);/* 打印發送出去的數據幀,調試用 */printf("MQTT_sendPacket:  \r\n");for (i = 0; i < len; i++) {printf("%x ", mqttBuff[i]);}printf("\r\n");memset_s(mqttBuff, sizeof(mqttBuff), 0, sizeof(mqttBuff));/* wait for connack */if (MQTTPacket_read(mqttBuff, sizeof(mqttBuff), transport_getdata) != CONNACK) {printf("MQTTPacket_read != CONNACK\r\n");}printf("MQTT_recvPacket:  \r\n");/* 打印服務器返回的消息,調試用 */for (i = 0; i < mqtt_read_len; i++) {printf("%x ", mqttBuff[i]);}printf("\r\n");if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, mqttBuff, sizeof(mqttBuff)) != 1 || connack_rc != 0) {printf("Unable to connect, return code %d\r\n", connack_rc);memset_s(mqttBuff, sizeof(mqttBuff), 0, sizeof(mqttBuff));return -1;} else {printf("MQTT initialized successfully\r\n");}memset_s(mqttBuff, sizeof(mqttBuff), 0, sizeof(mqttBuff));return 0;
}#define MQTT_PUB_DATA_TIME (100 * 1000)int MQTTClient_pub(char *pub_Topic, unsigned char *payloadData, int payloadLen)
{if (payloadData == NULL) {printf("Incorrect parameters\r\n");return -1;}printf("pubTopic: %s\n", pub_Topic);printf("pubData: %s\n", payloadData);int ret = 0, len = 0;unsigned short retry_count = 5; // 重發次數unsigned char sendBuff[MQTT_BUFF_MAX_SIZE] = {0};MQTTString topicString = MQTTString_initializer;topicString.cstring = pub_Topic;len = MQTTSerialize_publish(sendBuff, sizeof(sendBuff), 0, 0, 0, 0, topicString,payloadData,payloadLen);while (--retry_count > 0) {ret = transport_sendPacketBuffer(sendBuff, len);if (ret == 1) {break;}printf("Send MQTT_Data Fail\r\n");usleep(MQTT_PUB_DATA_TIME);}if (!retry_count && ret != 1) {printf("transport_sendPacketBuffer Error %d\r\n", ret);return -1;}// printf("send==>%s", payloadData);return 0;
}
unsigned char mqtt_topic[200];
int8_t (*p_MQTTClient_sub_callback)(unsigned char *topic, unsigned char *payload);int MQTTClient_sub(void)
{int qos, payloadlen_in;unsigned char dup, retained;unsigned short msgid;unsigned char *payload_in;MQTTString receivedTopic;memset_s(mqttBuff, sizeof(mqttBuff), 0, sizeof(mqttBuff));// $oc/devices/63ad5a6cc4efcc747bd75973_lamp/sys/commands/request_id=42c20ffb-0885-4f6e-97b5-45d8f613efafif (MQTTPacket_read(mqttBuff, sizeof(mqttBuff), transport_getdata) == PUBLISH) {MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,&payload_in, &payloadlen_in, mqttBuff, sizeof(mqttBuff));printf("data: %s\n", receivedTopic.lenstring.data);printf("length: %d\n", strlen(receivedTopic.lenstring.data) - payloadlen_in);printf("payload_length: %d\n", payloadlen_in);memcpy_s(mqtt_topic, sizeof(mqtt_topic),receivedTopic.lenstring.data, strlen(receivedTopic.lenstring.data) - payloadlen_in);printf("topic: %s\n", mqtt_topic);printf("payload: %s\n", payload_in);p_MQTTClient_sub_callback(mqtt_topic, payload_in);}
}

文件夾中創建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\network_15_mqtt\wifi_connecter.h文件,該頭文件包含wifi連接的宏。文件同tcp_12_client\wifi_connecter.h

文件夾中創建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\network_15_mqtt\wifi_connecter.c文件,文件同tcp_12_client\wifi_connecter.c

文件夾中創建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\network_15_mqtt\network_mqtt_example.c文件

/** Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**    http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#include <stdio.h>
#include <unistd.h>
#include <string.h>#include "ohos_init.h"
#include "cmsis_os2.h"
#include "network_mqtt.h"
#include "wifi_connecter.h"#define SERVER_IP_ADDR "192.168.137.1"
#define SERVER_IP_PORT 1883
#define MQTT_TOPIC_SUB "subTopic"
#define MQTT_TOPIC_PUB "pubTopic"
#define MQTT_CLIENT_ID "mqtt_client_123"
#define MQTT_USER_NAME "rtplay"
#define MQTT_PASSWORD "password"
#define TASK_STACK_SIZE (1024 * 5)
#define TASK_INIT_TIME 2 // s
#define MQTT_RECV_TASK_TIME (200 * 1000) // us
#define DELAY_TICKS_10     (10)osThreadId_t mqtt_send_task_id;   // mqtt訂閱數據任務
osThreadId_t mqtt_recv_task_id;   // mqtt發布數據任務
int8_t mqtt_sub_payload_callback(unsigned char *topic, unsigned char *payload)
{printf("[info] topic:[%s]    recv<== %s\r\n", topic, payload);
}
void mqtt_recv_task(void)
{while (1) {MQTTClient_sub();usleep(MQTT_RECV_TASK_TIME);}
}
void mqtt_send_task(void)
{// 連接WifiWifiDeviceConfig config = {0};// 準備AP的配置參數// strcpy(config.ssid, PARAM_HOTSPOT_SSID);// strcpy(config.preSharedKey, PARAM_HOTSPOT_PSK);strcpy_s(config.ssid, WIFI_MAX_SSID_LEN, PARAM_HOTSPOT_SSID);strcpy_s(config.preSharedKey, WIFI_MAX_KEY_LEN, PARAM_HOTSPOT_PSK);config.securityType = PARAM_HOTSPOT_TYPE;osDelay(DELAY_TICKS_10);int netId = ConnectToHotspot(&config);// 連接MQTT服務器if (MQTTClient_connectServer(SERVER_IP_ADDR, SERVER_IP_PORT) != 0) {printf("[error] MQTTClient_connectServer\r\n");} else {printf("[success] MQTTClient_connectServer\r\n");}sleep(TASK_INIT_TIME);// 初始化MQTT客戶端if (MQTTClient_init(MQTT_CLIENT_ID, MQTT_USER_NAME, MQTT_PASSWORD) != 0) {printf("[error] MQTTClient_init\r\n");} else {printf("[success] MQTTClient_init\r\n");}sleep(TASK_INIT_TIME);// 訂閱Topicif (MQTTClient_subscribe(MQTT_TOPIC_SUB) != 0) {printf("[error] MQTTClient_subscribe\r\n");} else {printf("[success] MQTTClient_subscribe\r\n");}sleep(TASK_INIT_TIME);osThreadAttr_t options;options.name = "mqtt_recv_task";options.attr_bits = 0;options.cb_mem = NULL;options.cb_size = 0;options.stack_mem = NULL;options.stack_size = TASK_STACK_SIZE;options.priority = osPriorityNormal;mqtt_recv_task_id = osThreadNew((osThreadFunc_t)mqtt_recv_task, NULL, &options);if (mqtt_recv_task_id != NULL) {printf("ID = %d, Create mqtt_recv_task_id is OK!\r\n", mqtt_recv_task_id);}while (1) {MQTTClient_pub(MQTT_TOPIC_PUB, "hello world!!!", strlen("hello world!!!"));sleep(TASK_INIT_TIME);}
}static void network_wifi_mqtt_example(void)
{printf("Enter network_wifi_mqtt_example()!\r\n");p_MQTTClient_sub_callback = &mqtt_sub_payload_callback;osThreadAttr_t options;options.name = "mqtt_send_task";options.attr_bits = 0;options.cb_mem = NULL;options.cb_size = 0;options.stack_mem = NULL;options.stack_size = TASK_STACK_SIZE;options.priority = osPriorityNormal;mqtt_send_task_id = osThreadNew((osThreadFunc_t)mqtt_send_task, NULL, &options);if (mqtt_send_task_id != NULL) {printf("ID = %d, Create mqtt_send_task_id is OK!\r\n", mqtt_send_task_id);}
}
SYS_RUN(network_wifi_mqtt_example);

使用build,編譯成功后,使用upload進行燒錄。

首先運行emqx

設置中文

運行后電腦ap會看到設備

串口會輸出

網頁中客戶端會看到模塊

主題也會看到

創建websocket連接服務

客戶端已經有了兩個

訂閱模塊的消息

可以收到模塊發送的消息

發送模塊訂閱的消息

模塊能收到消息

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/43390.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/43390.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/43390.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AutoMQ 生態集成 Kafdrop-ui

Kafdrop [1] 是一個為 Kafka 設計的簡潔、直觀且功能強大的Web UI 工具。它允許開發者和管理員輕松地查看和管理 Kafka 集群的關鍵元數據&#xff0c;包括主題、分區、消費者組以及他們的偏移量等。通過提供一個用戶友好的界面&#xff0c;Kafdrop 大大簡化了 Kafka 集群的監控…

量產工具一一UI系統(四)

目錄 前言 一、按鈕數據結構抽象 1.ui.h 二、按鍵處理 1.button.c 2.disp_manager.c 3.disp_manager.h 三、單元測試 1.ui_test.c 2.上機測試 前言 前面我們實現了顯示系統框架&#xff0c;輸入系統框架和文字系統框架&#xff0c;鏈接&#xff1a; 量產工具一一顯…

Redis 底層數據結構

? 簡單動態字符串 ? 鏈表 ? 字典 ? 跳躍表 ? 整數集合 ? 壓縮列表 ? 對象 SDS 增加了len和free屬性&#xff0c;記錄buf數組的使用空間和剩余空間。好處:strken函數直接讀取len值&#xff0c;時間復雜度是O(1)&#xff1b;預分配buf長度&#xf…

集控中心操作臺材質選擇如何選擇

作為集控中心的核心組成部分&#xff0c;操作臺不僅承載著各種設備和工具&#xff0c;更是工作人員進行監控、操作和管理的重要平臺。因此&#xff0c;選擇適合的集控中心操作臺材質顯得尤為重要。 一、材質選擇的考量因素 在選擇集控中心操作臺材質時&#xff0c;我們需要綜合…

SpringCloud跨微服務的遠程調用,如何發起網絡請求,RestTemplate

在我們的業務流程之中不一定都會是自己模塊查詢自己模塊的信息&#xff0c;有些時候就需要去結合其他模塊的信息來進行一些查詢完成相應的業務流程&#xff0c;但是在SpringCloud每個模塊都相對獨立&#xff0c;數據庫也有數據隔離。所以當我們需要其他微服務模塊的信息的時候&…

什么是SpringCloud Stream?

Spring Cloud Stream 是一個構建消息驅動微服務的框架&#xff0c;其基于Spring Boot來開發&#xff0c;并使用Spring Integration來連接消息代理中間件。該項目的目標是提供一套用于開發消息驅動應用的通用模型&#xff0c;并定義了用于發送和接收消息的綁定器&#xff08;Bin…

前端javascript中的排序算法之選擇排序

選擇排序&#xff08;Selection Sort&#xff09;基本思想&#xff1a; 是一種原址排序法&#xff1b; 將數組分為兩個區間&#xff1a;左側為已排序區間&#xff0c;右側為未排序區間。每趟從未排序區間中選擇一個值最小的元素&#xff0c;放到已排序區間的末尾&#xff0c;從…

玩轉springboot之為什么springboot可以直接執行

為什么springboot可以直接執行 先看一下springboot打包生成的MANIFEST.MF內容是什么 Manifest-Version: 1.0Implementation-Title: exam-adminImplementation-Version: 1.0-SNAPSHOTStart-Class: com.zhanghe.exam.ApplicationSpring-Boot-Classes: BOOT-INF/classes/Spring-Bo…

小米采取措施禁止國行版設備安裝國際版系統 刷機后將報錯無法進入系統

據知名官改版系統 Xiaomi.EU 測試者 Kacper Skrzypek 發布的消息&#xff0c;小米目前已經在開機引導中新增區域檢測機制&#xff0c;該機制將識別硬件所屬的市場版本&#xff0c;例如中國大陸市場銷售的小米即將在安裝國際版系統后將無法正常啟動。 測試顯示該檢測機制是在開…

1.DDR3 SO-DIMM 內存條硬件總結

最近在使用fpga讀寫DDR3&#xff0c;板子上的DDR3有兩種形式與fpga相連&#xff0c;一種是直接用ddr3內存顆粒&#xff0c;另一種是通過內存條的形式與fpga相連。這里我們正好記錄下和ddr3相關的知識&#xff0c;先從DDR3 SO-DIMM 內存條開始。 1.先看內存條的版本 從JEDEC下載…

四步帶你實現【Open3d】--邊緣檢測

Open3D邊緣檢測技術從3D數據中精準識別并提取邊界&#xff0c;對于場景解析、物體輪廓提取等任務至關重要。Open3D提供多種算法&#xff0c;幫助用戶高效實現邊緣檢測&#xff0c;促進3D數據的深度分析和應用。 一、安裝 pip install open3d # 即可 二、使用 首先&#…

《算法筆記》總結No.5——遞歸

一.分而治之 將原問題劃分為若干個規模較小而結構與原問題相同或相似的子問題&#xff0c;然后分別解決這些子問題&#xff0c;最后合并子問題的解&#xff0c;即可得到原問題的解&#xff0c;步驟抽象如下&#xff1a; 分解&#xff1a;將原問題分解為若干子問題解決&#x…

用VLM訓練實時計算機視覺模型

經過數十億個參數訓練的 AI 模型非常強大&#xff0c;但并不總是適合實時使用。但是&#xff0c;它們可以通過自動監督快速專用模型的標注來減少人力投入。 ? 如果你曾經構建過計算機視覺模型&#xff0c;就就會知道監督需要大量工作——人類花時間&#xff08;數小時或數天&a…

自動化測試全攻略:從入門到精通!

1、自動化測試專欄 隨著技術的發展和工作需求的增長&#xff0c;自動化測試已成為軟件質量保障體系中不可或缺的一環。 為了幫助廣大測試工程師、開發者和對自動化測試感興趣的讀者們更好地掌握這一技能&#xff0c;今年特別推出了全新的《自動化測試全攻略&#xff1a;從入門…

scratch繪制四個三角形 2024年6月中國電子學會 圖形化編程 scratch編程等級考試二級真題和答案解析

scratch繪制四個三角形 一、題目要求 2024年6月電子學會圖形化編程Scratch等級考試二級真題 1、準備工作 1.保留默認角色小貓; 2.添加背景Stars。 2、功能實現 1 .隱藏角色小貓&#xff0c;設置畫筆裙始位置為(0,0)&#xff0c;畫筆顏色為黃色&#xff0c;畫筆的粗細為5…

Scala Trait(特征)

Scala Trait(特征) Scala中的Trait是一種特殊的概念,它類似于Java中的接口,但提供了更多的功能。Trait允許我們定義一組方法,這些方法可以被子類實現,同時還可以包含方法的實現。這使得Trait既具有接口的靈活性,又具有抽象類的實用性。在本文中,我們將深入探討Scala Tra…

NET Core 中的空對象設計模式

介紹 一種稱為“空對象模式”的行為設計模式提供了一個對象來表示接口缺少的對象。在空對象會導致空引用異常的情況下&#xff0c;這是一種提供替代行為的方法。在本文中&#xff0c;我們將深入探討 C# 空對象模式&#xff0c;并逐步解決更復雜的情況。 空對象設計模式它是什…

k8s離線部署芋道源碼前端

目錄 概述 編譯Dockerfile 構建Dockerfilenginx.conf構建 k8s部署前端鏡像部署ingress 概述 本篇將對 k8s離線部署芋道源碼前端 進行詳細的說明&#xff0c;對如何構建 Dockerfile&#xff0c;如何整合 Nginx&#xff0c;如何整合 ingress 進行實踐。 相關文章&#xff1a;naco…

python 進階教程--PIL圖像處理

PIL圖像處理 1. Pillow庫簡介2. 圖像處理基礎3. 圖像操作4. 圖像增強5. 圖像處理進階6. 圖像繪制7. 圖像序列和動畫8. 圖像識別和特征提取9. 實戰項目10. 常見問題解答 1. Pillow庫簡介 PIL與Pillow的關系 PIL&#xff08;Python Imaging Library&#xff09;是一個提供圖像處…

【云原生之kubernetes實戰】在k8s環境下部署OrangeHRM人力資源管理系統

【云原生之kubernetes實戰】在k8s環境下部署OrangeHRM人力資源管理系統 一、OrangeHRM介紹1.1 OrangeHRM 簡介1.2 OrangeHRM特點1.3 OrangeHRM使用場景二、相關知識介紹2.1 本次實踐存儲介紹2.2 k8s存儲介紹三、本次實踐介紹3.1 本次實踐簡介3.2 本次環境規劃3.3 部署前需準備工…