【Qt】modbus客戶端筆記

Qt 中基于 Modbus 協議的通用客戶端學習筆記

一、概述

本客戶端利用 Qt 的 QModbusTcpClient 實現與 Modbus 服務器的通信,具備連接、讀寫寄存器、心跳檢測、自動重連等功能,旨在提供一個可靠且易用的 Modbus 客戶端框架,方便在不同項目中集成使用。

二、核心功能實現

(一)初始化

  1. 在構造函數中:
    • 首先初始化基類 QObject,確保對象層次結構正確構建。
    • 實例化 m_modbusClient,將自身作為其父對象,以便管理內存。
    • 創建 m_heartbeatTimerm_reconnectTimer,并設置心跳間隔(如 2 秒)和自動重連間隔(如 2 秒)。
    • 連接相關信號與槽:
      • m_heartbeatTimer 超時,觸發 checkHeartbeat 槽函數,用于檢測心跳。
      • m_reconnectTimer 超時,觸發 attemptReconnect 槽函數,嘗試重新連接服務器。
      • m_modbusClient 的狀態改變時,連接到 handleStateChanged 槽函數,以便及時更新設備連接狀態。

(二)連接管理

  1. 獲取連接狀態
    • getStatus 函數通過查詢 m_modbusClient 的當前狀態(QModbusDevice::State),將其轉換為自定義的 DeviceStatus(如 ConnectedConnectingDisconnected)枚舉類型,并返回。這有助于上層代碼了解設備的實時連接情況。
  2. 連接設備
    • connectDevice 函數首先從 m_properties 中獲取存儲的 IP 地址和端口信息,分別設置到 m_modbusClient 的連接參數中(使用 QModbusDevice::NetworkAddressParameterQModbusDevice::NetworkPortParameter),然后調用 m_modbusClientconnectDevice 方法嘗試建立連接。根據連接結果,通過 setStatus 函數更新設備狀態。
  3. 斷開連接
    • disconnectDevice 函數調用 m_modbusClientdisconnectDevice 方法斷開與服務器的連接,同時停止心跳定時器和自動重連定時器,并更新設備狀態為 Disconnected

(三)讀寫寄存器

  1. 寫寄存器
    • writeRegisters 函數首先檢查設備是否已連接(通過 m_modbusClient 的狀態判斷),若未連接則打印錯誤信息并返回 false。接著,構建 QModbusDataUnit 對象,設置要寫入的寄存器類型、起始地址以及數據值。然后,通過 m_modbusClient 發送寫請求,并連接到回復信號,在回復完成后根據錯誤碼判斷寫入操作是否成功。
  2. 讀寄存器
    • readRegisters 函數同樣先檢查設備連接狀態,若未連接則打印錯誤信息并返回。構建 QModbusDataUnit 對象指定要讀取的寄存器類型、起始地址和數量,然后通過 m_modbusClient 發送讀請求,并連接到 onAllRegistersReadReady 槽函數,等待讀取結果。

(四)心跳檢測與自動重連

  1. 心跳檢測
    • checkHeartbeat 函數在心跳定時器超時時觸發。它首先檢查設備是否仍處于連接狀態,若不是則直接處理連接斷開情況(調用 handleStateChanged 函數將狀態設為 Unconnected)。若連接正常,則向服務器發送一個簡單的讀寄存器請求(通常讀取保持寄存器的特定位置,如 0 地址,長度為 1),通過回復的錯誤碼判斷連接是否依然存活,若有錯誤則同樣處理連接斷開。
  2. 自動重連
    • attemptReconnect 函數在自動重連定時器超時時執行。它檢查設備是否未連接,若是,則嘗試重新連接(調用 connectDevice 函數),并記錄重連次數。若重連次數達到預設上限(如 MAX_RECONNECT_ATTEMPTS),則停止自動重連定時器,防止無意義的重復嘗試。

三、信號與槽

  1. m_modbusClient 的狀態改變時,handleStateChanged 槽函數被觸發,根據不同的狀態(UnconnectedStateConnectedStateConnectingState)更新設備的自定義連接狀態,并觸發相應操作,如啟動或停止定時器。
  2. 在讀寄存器操作完成后,onAllRegistersReadReady 槽函數被調用,它從 QModbusReply 中獲取讀取結果數據單元 QModbusDataUnit,并通過信號 allRegistersReadCompleted 將結果發射出去,供外部代碼進一步處理。

歡迎大家提供優化建議。

#ifndef MODBUSDEVICE_H
#define MODBUSDEVICE_H#include <QObject>
#include <QModbusTcpClient>
#include <QTimer>
#include <QMap>
#include <QVariant>// 定義設備狀態的枚舉類型,用于表示 Modbus 設備當前的連接狀態
enum class DeviceStatus {Disconnected,  // 設備處于斷開連接狀態Connecting,    // 設備正在嘗試連接Connected      // 設備已成功連接
};// ModbusDevice 類繼承自 QObject,用于管理 Modbus TCP 客戶端的連接和通信
class ModbusDevice : public QObject
{Q_OBJECT
public:// 構造函數,接受一個包含設備屬性的 QMap 和可選的父對象指針// properties: 包含設備屬性的 QMap,如設備 ID、IP 地址、端口等// parent: 父對象指針,默認為 nullptrexplicit ModbusDevice(const QMap<QString, QVariant>& properties, QObject *parent = nullptr);// 析構函數,負責釋放動態分配的資源~ModbusDevice();// 獲取設備當前的連接狀態DeviceStatus getStatus();// 獲取設備的重連嘗試次數int deviceReconnectAttempts() const;// 設置設備的屬性值// key: 屬性的鍵,如 "deviceID", "ipAddress" 等// value: 屬性的值void setProperty(const QString& key, const QVariant& value);// 獲取設備的屬性值// key: 屬性的鍵// 返回值: 屬性的值,如果鍵不存在則返回默認值QVariant getProperty(const QString& key) const;// 向 Modbus 設備寫入寄存器數據// registerType: 寄存器類型,如 QModbusDataUnit::HoldingRegisters// registerAddress: 寄存器的起始地址// values: 要寫入的寄存器值的向量// 返回值: 寫入操作是否成功bool writeRegisters(QModbusDataUnit::RegisterType registerType, quint16 registerAddress, const QVector<quint16>& values);// 從 Modbus 設備讀取寄存器數據// registerType: 寄存器類型// registerAddress: 寄存器的起始地址// count: 要讀取的寄存器數量void readRegisters(QModbusDataUnit::RegisterType registerType, quint16 registerAddress, quint16 count);// 嘗試連接到 Modbus 設備// 返回值: 連接是否成功bool connectDevice();// 斷開與 Modbus 設備的連接void disconnectDevice();// 獲取設備的 IDint deviceId() const;// 獲取設備的 IP 地址QString deviceAddress() const;// 獲取設備的名稱QString deviceName() const;// 獲取設備的端口號quint16 devicePort() const;signals:// 當設備連接狀態發生變化時發出的信號,攜帶設備 ID// deviceId: 設備的 IDvoid signal_DeviceConnectState(int deviceId);// 當所有寄存器讀取完成時發出的信號,攜帶讀取到的數據單元// unit: 包含讀取結果的 QModbusDataUnitvoid allRegistersReadCompleted(const QModbusDataUnit& unit);private slots:// 心跳檢測槽函數,定期檢查設備的連接狀態void checkHeartbeat();// 嘗試重新連接設備的槽函數,在連接斷開時調用void attemptReconnect();// 處理 Modbus 客戶端狀態變化的槽函數// state: 新的 Modbus 設備狀態void handleStateChanged(QModbusDevice::State state);// 處理寄存器讀取完成的槽函數void onAllRegistersReadReady();// 設置設備的連接狀態,并執行相應的操作// newStatus: 新的設備連接狀態void setStatus(DeviceStatus newStatus);private:// 存儲設備屬性的 QMap,如設備 ID、IP 地址、端口等QMap<QString, QVariant> m_properties;// Modbus TCP 客戶端指針,用于與 Modbus 設備進行通信QModbusTcpClient* m_modbusClient;// 心跳檢測定時器,定期觸發心跳檢測QTimer* m_heartbeatTimer;// 重連定時器,在連接斷開時定期嘗試重新連接QTimer* m_reconnectTimer;// 設備當前的連接狀態DeviceStatus m_status;// 記錄設備的重連嘗試次數int m_reconnectAttempts = 0;// 最大重連嘗試次數,超過該次數將停止重連static const int MAX_RECONNECT_ATTEMPTS = 5;
};#endif // MODBUSDEVICE_H    
#include "modbusdevice.h"
#include <QDebug>// 構造函數實現
ModbusDevice::ModbusDevice(const QMap<QString, QVariant>& properties, QObject *parent): QObject(parent),m_properties(properties),m_modbusClient(new QModbusTcpClient(this)),m_status(DeviceStatus::Disconnected)
{// 創建心跳檢測定時器,并設置定時器的父對象為當前對象m_heartbeatTimer = new QTimer(this);// 設置心跳檢測定時器的間隔為 2000 毫秒(即 2 秒)m_heartbeatTimer->setInterval(2000);// 連接心跳檢測定時器的超時信號到 checkHeartbeat 槽函數connect(m_heartbeatTimer, &QTimer::timeout, this, &ModbusDevice::checkHeartbeat);// 創建重連定時器,并設置定時器的父對象為當前對象m_reconnectTimer = new QTimer(this);// 設置重連定時器的間隔為 2000 毫秒(即 2 秒)m_reconnectTimer->setInterval(2000);// 連接重連定時器的超時信號到 attemptReconnect 槽函數connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusDevice::attemptReconnect);// 連接 Modbus 客戶端的狀態變化信號到 handleStateChanged 槽函數connect(m_modbusClient, &QModbusTcpClient::stateChanged, this, &ModbusDevice::handleStateChanged);
}// 析構函數實現
ModbusDevice::~ModbusDevice()
{// 釋放 Modbus 客戶端對象的內存delete m_modbusClient;
}// 獲取設備狀態的函數實現
DeviceStatus ModbusDevice::getStatus()
{// 獲取 Modbus 客戶端的當前狀態QModbusDevice::State state = m_modbusClient->state();if (state == QModbusDevice::ConnectedState) {// 如果 Modbus 客戶端已連接,設置設備狀態為 ConnectedsetStatus(DeviceStatus::Connected);} else if (state == QModbusDevice::ConnectingState) {// 如果 Modbus 客戶端正在連接,設置設備狀態為 ConnectingsetStatus(DeviceStatus::Connecting);} else if (state == QModbusDevice::UnconnectedState) {// 如果 Modbus 客戶端未連接,設置設備狀態為 DisconnectedsetStatus(DeviceStatus::Disconnected);}// 返回設備的當前狀態return m_status;
}// 獲取設備重連嘗試次數的函數實現
int ModbusDevice::deviceReconnectAttempts() const
{// 返回設備的重連嘗試次數return m_reconnectAttempts;
}// 設置設備屬性的函數實現
void ModbusDevice::setProperty(const QString& key, const QVariant& value)
{// 將屬性鍵值對添加到 m_properties 中m_properties[key] = value;
}// 獲取設備屬性的函數實現
QVariant ModbusDevice::getProperty(const QString& key) const
{// 從 m_properties 中獲取指定鍵的屬性值return m_properties.value(key);
}// 寫入寄存器的函數實現
bool ModbusDevice::writeRegisters(QModbusDataUnit::RegisterType registerType, quint16 registerAddress, const QVector<quint16>& values)
{if (m_modbusClient->state() != QModbusDevice::ConnectedState) {// 如果 Modbus 客戶端未連接,輸出錯誤信息并返回 falseqDebug() << "Device is not connected. Cannot write registers.";return false;}// 創建一個 Modbus 數據單元,用于寫入寄存器QModbusDataUnit writeUnit(registerType, registerAddress, values.size());for (int i = 0; i < values.size(); ++i) {// 將值寫入 Modbus 數據單元writeUnit.setValue(i, values[i]);}// 發送寫入請求,并獲取響應對象QModbusReply* reply = m_modbusClient->sendWriteRequest(writeUnit, m_properties["deviceID"].toInt());if (reply) {// 連接響應對象的完成信號到一個 lambda 函數connect(reply, &QModbusReply::finished, [reply]() {if (reply->error() != QModbusDevice::NoError) {// 如果寫入過程中出現錯誤,輸出錯誤信息qDebug() << "Modbus write registers error:" << reply->errorString();} else {// 如果寫入成功,輸出成功信息qDebug() << "Modbus write registers success:";}// 釋放響應對象的內存reply->deleteLater();});// 返回寫入操作成功return true;} else {// 如果發送寫入請求失敗,輸出錯誤信息并返回 falseqDebug() << "Failed to send write registers request";return false;}
}// 讀取寄存器的函數實現
void ModbusDevice::readRegisters(QModbusDataUnit::RegisterType registerType, quint16 registerAddress, quint16 count)
{if (m_modbusClient->state() != QModbusDevice::ConnectedState) {// 如果 Modbus 客戶端未連接,輸出錯誤信息并返回qDebug() << "Device is not connected. Cannot read registers.";return;}// 創建一個 Modbus 數據單元,用于讀取寄存器QModbusDataUnit readUnit(registerType, registerAddress, count);// 發送讀取請求,并獲取響應對象QModbusReply* reply = m_modbusClient->sendReadRequest(readUnit, m_properties["deviceID"].toInt());if (reply) {// 連接響應對象的完成信號到 onAllRegistersReadReady 槽函數connect(reply, &QModbusReply::finished, this, &ModbusDevice::onAllRegistersReadReady);} else {// 如果發送讀取請求失敗,輸出錯誤信息qDebug() << "Failed to send read registers request";}
}// 設置設備狀態的函數實現
void ModbusDevice::setStatus(DeviceStatus newStatus)
{if (m_status != newStatus) {// 如果新狀態與當前狀態不同m_status = newStatus;// 發出設備連接狀態變化的信號,攜帶設備 IDemit signal_DeviceConnectState(m_properties["deviceID"].toInt());if (m_status == DeviceStatus::Connected) {// 如果設備已連接,啟動心跳檢測定時器m_heartbeatTimer->start();// 重置重連嘗試次數m_reconnectAttempts = 0;} else if (m_status == DeviceStatus::Disconnected) {// 如果設備斷開連接,停止心跳檢測定時器m_heartbeatTimer->stop();if (m_reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {// 如果重連嘗試次數未達到最大次數,啟動重連定時器m_reconnectTimer->start();}}}
}// 處理 Modbus 客戶端狀態變化的槽函數實現
void ModbusDevice::handleStateChanged(QModbusDevice::State state)
{switch (state) {case QModbusDevice::UnconnectedState:// 如果 Modbus 客戶端未連接,設置設備狀態為 DisconnectedsetStatus(DeviceStatus::Disconnected);break;case QModbusDevice::ConnectedState:// 如果 Modbus 客戶端已連接,設置設備狀態為 ConnectedsetStatus(DeviceStatus::Connected);break;case QModbusDevice::ConnectingState:// 如果 Modbus 客戶端正在連接,設置設備狀態為 ConnectingsetStatus(DeviceStatus::Connecting);break;default:break;}
}// 心跳檢測槽函數實現
void ModbusDevice::checkHeartbeat()
{if (m_modbusClient->state() != QModbusDevice::ConnectedState) {// 如果 Modbus 客戶端未連接,處理設備斷開連接的情況handleStateChanged(QModbusDevice::UnconnectedState);return;}// 創建一個 Modbus 數據單元,用于讀取心跳寄存器QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0, 1);// 發送讀取請求,并獲取響應對象QModbusReply* reply = m_modbusClient->sendReadRequest(readUnit, m_properties["deviceID"].toInt());if (reply) {// 連接響應對象的完成信號到一個 lambda 函數connect(reply, &QModbusReply::finished, this, [this, reply]() {if (reply->error() != QModbusDevice::NoError) {// 如果讀取過程中出現錯誤,處理設備斷開連接的情況handleStateChanged(QModbusDevice::UnconnectedState);}// 釋放響應對象的內存reply->deleteLater();});} else {// 如果發送讀取請求失敗,處理設備斷開連接的情況handleStateChanged(QModbusDevice::UnconnectedState);}
}// 嘗試重新連接設備的槽函數實現
void ModbusDevice::attemptReconnect()
{if (m_modbusClient->state() != QModbusDevice::ConnectedState) {// 如果 Modbus 客戶端未連接,輸出重連嘗試信息qDebug() << "嘗試重連設備 ID:" << m_properties["deviceID"].toInt();if (m_reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {// 如果重連嘗試次數未達到最大次數,嘗試重新連接設備connectDevice();// 增加重連嘗試次數m_reconnectAttempts++;} else {// 如果重連嘗試次數達到最大次數,輸出重連失敗信息并停止重連定時器qDebug() << "設備 ID:" << m_properties["deviceID"].toInt() << " 重連次數達到上限,停止重連";m_reconnectTimer->stop();}}
}// 處理寄存器讀取完成的槽函數實現
void ModbusDevice::onAllRegistersReadReady()
{// 獲取發送信號的對象,并將其轉換為 QModbusReply 指針QModbusReply* reply = qobject_cast<QModbusReply*>(sender());if (!reply) {// 如果轉換失敗,輸出錯誤信息并返回qDebug() << "Invalid reply object";return;}if (reply->error() != QModbusDevice::NoError) {// 如果讀取過程中出現錯誤,輸出錯誤信息qDebug() << "Modbus read all registers error:" << reply->errorString();} else {// 如果讀取成功,獲取讀取結果并發出所有寄存器讀取完成的信號QModbusDataUnit unit = reply->result();emit allRegistersReadCompleted(unit);}// 釋放響應對象的內存reply->deleteLater();
}// 連接設備的函數實現
bool ModbusDevice::connectDevice()
{// 從設備屬性中獲取 IP 地址QString ipAddress = m_properties["ipAddress"].toString();// 從設備屬性中獲取端口號quint16 port = m_properties["port"].toUInt();// 設置 Modbus 客戶端的網絡地址參數m_modbusClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, ipAddress);// 設置 Modbus 客戶端的網絡端口參數m_modbusClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);// 嘗試連接 Modbus 設備,并獲取連接結果bool result = m_modbusClient->connectDevice();if (m_modbusClient->state() == QModbusDevice::ConnectedState) {// 如果 Modbus 客戶端已連接,設置設備狀態為 ConnectedsetStatus(DeviceStatus::Connected);} else {// 如果 Modbus 客戶端未連接,設置設備狀態為 DisconnectedsetStatus(DeviceStatus::Disconnected);}// 返回連接結果return result;
}
// 斷開設備連接的函數實現
void ModbusDevice::disconnectDevice()
{// 斷開 Modbus 客戶端與設備的連接m_modbusClient->disconnectDevice();// 設置設備狀態為 DisconnectedsetStatus(DeviceStatus::Disconnected);// 停止心跳檢測定時器m_heartbeatTimer->stop();// 停止重連定時器m_reconnectTimer->stop();
}
// 獲取設備 ID 的函數實現
int ModbusDevice::deviceId() const
{// 從設備屬性中獲取設備 IDreturn m_properties["deviceID"].toInt();
}
// 獲取設備 IP 地址的函數實現
QString ModbusDevice::deviceAddress() const
{// 從設備屬性中獲取設備 IP 地址return m_properties["ipAddress"].toString();
}
// 獲取設備名稱的函數實現
QString ModbusDevice::deviceName() const
{// 從設備屬性中獲取設備名稱return m_properties["deviceName"].toString();
}
// 獲取設備端口號的函數實現
quint16 ModbusDevice::devicePort() const
{// 從設備屬性中獲取設備端口號return m_properties["port"].toInt();
}    
#include "modbusdevice.h"
#include <QCoreApplication>
#include <QDebug>int main(int argc, char *argv[])
{// 創建一個 QCoreApplication 對象,用于管理應用程序的生命周期QCoreApplication a(argc, argv);// 創建一個 QMap 對象,用于存儲 Modbus 設備的屬性QMap<QString, QVariant> properties;// 設置設備的 ID 為 1properties["deviceID"] = 1;// 設置設備的 IP 地址為本地回環地址properties["ipAddress"] = "127.0.0.1";// 設置設備的端口號為 502properties["port"] = 502;// 設置設備的名稱為 "TestDevice"properties["deviceName"] = "TestDevice";// 創建一個 ModbusDevice 對象,傳入設備屬性ModbusDevice device(properties);// 嘗試連接 Modbus 設備if (device.connectDevice()) {// 如果連接成功,輸出連接成功信息qDebug() << "設備連接成功";// 創建一個 QVector 對象,存儲要寫入寄存器的值QVector<quint16> values = {1, 2, 3};// 調用 writeRegisters 函數,向設備的保持寄存器寫入數據device.writeRegisters(QModbusDataUnit::HoldingRegisters, 0, values);// 調用 readRegisters 函數,從設備的保持寄存器讀取數據device.readRegisters(QModbusDataUnit::HoldingRegisters, 0, 3);// 連接 allRegistersReadCompleted 信號到一個 lambda 函數// 當寄存器讀取完成時,輸出讀取到的值QObject::connect(&device, &ModbusDevice::allRegistersReadCompleted, [](const QModbusDataUnit& unit) {qDebug() << "讀取寄存器完成,值為:" << unit.values();});} else {// 如果連接失敗,輸出連接失敗信息qDebug() << "設備連接失敗";}// 進入應用程序的事件循環,等待事件發生return a.exec();
}    

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

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

相關文章

解決Vmware 運行虛擬機Ubuntu22.04卡頓、終端打字延遲問題

親測可用 打開虛擬機設置&#xff0c;關閉加速3D圖形 &#xff08;應該是顯卡驅動的問題&#xff0c;不知道那個版本的驅動不會出現這個問題&#xff0c;所以干脆把加速關了&#xff09;

【網絡】Socket套接字

目錄 一、端口號 二、初識TCP/UDP協議 三、網絡字節序 3.1 概念 3.2 常用API 四、Socket套接字 4.1 概念 4.2 常用API &#xff08;1&#xff09;socket &#xff08;2&#xff09;bind sockaddr結構 &#xff08;3&#xff09;listen &#xff08;4&#xff09;a…

內聯函數/函數重載/函數參數缺省

一、內聯函數 為了減少函數調用的開銷 在函數定義前加“inline”關鍵字&#xff0c;即可定義內聯函數 二、函數重載 1.名字相同 2.參數個數或者參數類型不同 編譯器根據調用語句實參的個數和類型判斷應該調用哪個函數 三、函數的缺省參數 定義函數的時候可以讓最右邊的連…

基于神經網絡的文本分類的設計與實現

標題:基于神經網絡的文本分類的設計與實現 內容:1.摘要 在信息爆炸的時代&#xff0c;大量文本數據的分類處理變得至關重要。本文旨在設計并實現一種基于神經網絡的文本分類系統。通過構建合適的神經網絡模型&#xff0c;采用公開的文本數據集進行訓練和測試。在實驗中&#x…

Baklib內容中臺的核心定位是什么?

構建企業級知識中樞 在數字化轉型趨勢下&#xff0c;Baklib內容中臺通過構建企業級知識中樞&#xff0c;實現了從碎片化信息到體系化資產的躍遷。其核心能力體現為對多源內容的智能聚合與結構化存儲&#xff0c;支持從文檔、圖片到視頻的全格式整合&#xff0c;并通過語義標簽…

藍耘平臺API深度剖析:如何高效實現AI應用聯動

目錄 一、藍耘平臺簡介 1.1 藍耘通義大模型 1.2 藍耘云計算資源 1.3 藍耘API與微服務 二、 藍耘平臺應用聯動場景 2.1 數據采集與預處理聯動 2.2 模型推理與后端服務聯動 2.3 跨平臺聯動 三、藍耘平臺注冊體驗功能 3.1 注冊 3.2 體驗藍耘MaaS平臺如何使用海螺AI生成視頻…

《大語言模型賦能證券業開發安全:海云安技術方案在上交所專刊發表》

近日&#xff0c;海云安《大語言模型在證券業開發安全領域的探索與實踐》技術方案經過上海證券交易所&#xff08;以下簡稱”上交所“&#xff09;行業專家評審后正式收錄于《交易技術前沿——網絡安全專刊&#xff08;2025年第1期 總第61期&#xff09;》。 證券信息技術研究…

第三課:Stable Diffusion圖生圖入門及應用

文章目錄 Part01 圖生圖原理Part02 圖生圖基本流程Part03 隨機種子作用解析Part04 圖生圖的拓展應用 Part01 圖生圖原理 當提示詞不能足夠表達用戶需求的時候&#xff0c;加入圖片能讓AI更好的理解你的想法圖片上的像素信息會在加噪和去噪的過程中&#xff0c;作為一種特征反映…

將網絡安全和第三方風險管理與業務目標相結合

在網絡安全風險領域&#xff0c;我們經常遇到與企業語言不通的問題。這可能導致網絡安全風險管理計劃得不到支持。當發現網絡安全風險時&#xff0c;困難在于以符合組織語言和目標的方式來表達它。 第三方風險屬于另一個灰色地帶。在組織內部&#xff0c;許多利益相關者&#…

使用Github項目nghttp3的樣例學習HTTP/3

文章目錄 前言一、HTTP3測試 in Ubuntu1.1. 基本軟件1.2. gcc/g1.2.1. Ubuntu221.2.2. Ubuntu201.2.2.1. 必備庫1.2.2.1.1. gmp1.2.2.1.2. mpfr1.2.2.1.3. mpc 1.2.2.2. 安裝 1.3. libev > 4.11&#xff08;備用&#xff09;1.3.1. 安裝1.3.2. 測試 1.4. nghttp31.5. ngtcp2…

uniapp 在app上 字體如何不跟著系統字體大小變

在UniApp開發中&#xff0c;默認情況下App的字體可能會跟隨系統字體設置而變化。如果你希望保持固定的字體樣式&#xff0c;不隨系統字體設置改變&#xff0c;可以采用以下幾種方法&#xff1a; 方法一&#xff1a;全局CSS設置 在App.vue的樣式中添加以下CSS&#xff1a; /*…

跨域問題的解決方案

一、跨域問題的本質 1.1 同源策略的三要素 瀏覽器的同源策略&#xff08;Same-Origin Policy&#xff09;要求請求的 協議、域名、端口 完全一致&#xff0c;否則視為跨域&#xff1a; 協議不同&#xff1a;http 與 https域名不同&#xff1a;a.com 與 b.com端口不同&#x…

Linux 上使用 Docker 部署 Kafka 集群

在 Linux 上使用 Docker 部署 Kafka 集群的步驟如下 1. 準備工作 確保已安裝&#xff1a; Docker Docker Compose 2. 創建 Docker Compose 文件 (docker-compose.yml) version: 3.8services:zookeeper:image: wurstmeister/zookeepercontainer_name: zookeeperports:- &quo…

【性能優化點滴】odygrd/quill 中一個簡單的標記位作用--降低 IO 次數

在 StreamSink 類中&#xff0c;成員變量 _write_occurred 的作用是 跟蹤自上次刷新&#xff08;Flush&#xff09;以來是否有寫入操作發生&#xff0c;其核心目的是 優化 I/O 性能。以下是詳細解析&#xff1a; _write_occurred 的作用 1. 避免不必要的刷新&#xff08;Flush…

Ubuntu Linux安裝PyQt5并配置Qt Designer

一 安裝 PyQt5 借助 apt 包管理器來安裝 PyQt5 及其相關的開發工具&#xff1a; sudo apt install python3-pyqt5 pyqt5-dev-tools 假如報錯&#xff0c; You might want to run apt --fix-broken install to correct these. 直接執行&#xff1a; sudo apt --fix-…

2025清華大學:DeepSeek教程全集(PDF+視頻精講,共10份).zip

一、資料列表 第一課&#xff1a;Deepseek基礎入門 第二課&#xff1a;DeepSeek賦能職場 第三課&#xff1a;普通人如何抓住DeepSeek紅利 第四課&#xff1a;讓科研像聊天一樣簡單 第五課&#xff1a;DeepSeek與AI幻覺 第六課&#xff1a;基于DeepSeek的AI音樂詞曲的創造法 第…

容器C++

string容器 string構造函數 #include<iostream> using namespace std; #include<string.h> void test01() {string s1;//默認構造const char* str "hello world";string s2(str);//傳入char*cout << "s2" << s2 << endl;s…

【2.項目管理】2.4 Gannt圖【甘特圖】

甘特圖&#xff08;Gantt&#xff09;深度解析與實踐指南 &#x1f4ca; 一、甘特圖基礎模板 項目進度表示例 工作編號工作名稱持續時間(月)項目進度&#xff08;周&#xff09;1需求分析3▓▓▓???????2設計建模3?▓▓▓??????3編碼開發3.5???▓▓▓▓??…

C++List模擬實現|細節|難點|易錯點|全面解析|類型轉換|

目錄 1.模擬代碼全部 2.四大塊代碼理解 1.最底層&#xff1a;ListNode部分 2.第二層&#xff1a;ListIterator部分 3.第三層&#xff1a;ReserveListIterator部分 4最終層&#xff1a;List 1.模擬代碼全部 using namespace std; template<class T> struct ListNode …

【深度學習與實戰】2.1、線性回歸模型與梯度下降法先導

import numpy as np# 數據準備 X np.array([1, 2, 3]) y np.array([3, 5, 7])# 參數初始化 w0, w1 0, 0 alpha 0.1 n len(X)# 迭代10次 for epoch in range(10):# 計算預測值y_pred w1 * X w0# 計算梯度grad_w0 (1/n) * np.sum(y_pred - y)grad_w1 (1/n) * np.sum((y_…