Qt 與 WebService 交互開發

在現代軟件開發中,WebService 已成為實現跨平臺、跨語言通信的重要標準。Qt 作為一個強大的跨平臺框架,提供了完善的工具和類庫來實現與 WebService 的交互。本文將深入探討 Qt 與 WebService 交互開發的核心技術和實踐經驗,包括 SOAP 協議實現、RESTful API 調用、XML 數據處理以及安全認證等方面。

一、SOAP WebService 基礎

1. SOAP 消息結構

SOAP (Simple Object Access Protocol) 是一種基于 XML 的協議,用于在網絡上交換結構化數據。典型的 SOAP 消息結構如下:

<?xml version="1.0"?>
<soap:Envelopexmlns:soap="http://www.w3.org/2003/05/soap-envelope"soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding"><soap:Header><!-- 可選的頭部信息,如認證信息 --></soap:Header><soap:Body><!-- 消息主體,包含具體的請求或響應數據 --><m:GetStockPrice xmlns:m="http://www.example.org/stock"><m:StockName>IBM</m:StockName></m:GetStockPrice></soap:Body></soap:Envelope>
2. Qt 實現 SOAP 客戶端
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QEventLoop>class SoapClient : public QObject {Q_OBJECT
public:explicit SoapClient(QObject *parent = nullptr) : QObject(parent) {manager = new QNetworkAccessManager(this);}// 同步調用 SOAP 服務QMap<QString, QString> callSoapService(const QString &serviceUrl, const QString &soapAction,const QString &methodName,const QMap<QString, QString> &parameters) {// 創建 SOAP 請求QByteArray soapRequest = createSoapRequest(methodName, parameters);// 設置請求頭QNetworkRequest request(QUrl(serviceUrl));request.setHeader(QNetworkRequest::ContentTypeHeader, "application/soap+xml; charset=utf-8");request.setRawHeader("SOAPAction", soapAction.toUtf8());// 發送請求QNetworkReply *reply = manager->post(request, soapRequest);// 等待響應QEventLoop loop;connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);loop.exec();// 處理響應QMap<QString, QString> result;if (reply->error() == QNetworkReply::NoError) {QByteArray responseData = reply->readAll();parseSoapResponse(responseData, result);} else {result["error"] = reply->errorString();}reply->deleteLater();return result;}private:// 創建 SOAP 請求QByteArray createSoapRequest(const QString &methodName, const QMap<QString, QString> &parameters) {QByteArray data;QXmlStreamWriter xml(&data);xml.setAutoFormatting(true);xml.writeStartDocument();xml.writeStartElement("soap", "Envelope");xml.writeNamespace("http://www.w3.org/2003/05/soap-envelope", "soap");xml.writeNamespace("http://tempuri.org/", "tem");xml.writeStartElement("soap", "Body");xml.writeStartElement("tem", methodName);// 添加參數for (auto it = parameters.begin(); it != parameters.end(); ++it) {xml.writeTextElement("tem", it.key(), it.value());}xml.writeEndElement(); // methodNamexml.writeEndElement(); // Bodyxml.writeEndElement(); // Envelopexml.writeEndDocument();return data;}// 解析 SOAP 響應void parseSoapResponse(const QByteArray &responseData, QMap<QString, QString> &result) {QXmlStreamReader xml(responseData);while (!xml.atEnd() && !xml.hasError()) {QXmlStreamReader::TokenType token = xml.readNext();if (token == QXmlStreamReader::StartElement) {// 查找響應元素if (xml.name() == "GetStockPriceResponse") {// 解析響應內容while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "GetStockPriceResponse")) {if (xml.tokenType() == QXmlStreamReader::StartElement) {if (xml.name() == "GetStockPriceResult") {result["price"] = xml.readElementText();}}xml.readNext();}}}}if (xml.hasError()) {result["error"] = xml.errorString();}}private:QNetworkAccessManager *manager;
};

二、使用 Qt SOAP 模塊

1. 配置 Qt SOAP 模塊

Qt 5 及以前版本提供了 QtSOAP 模塊,但在 Qt 6 中已被移除。如果使用 Qt 5,可以通過以下方式配置:

# CMakeLists.txt
find_package(Qt5 COMPONENTS Network REQUIRED)
target_link_libraries(myapp PRIVATE Qt5::Network)
2. Qt SOAP 模塊示例
#include <QtSoapMessage>
#include <QtSoapTransport>
#include <QCoreApplication>
#include <QDebug>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 創建 SOAP 請求QtSoapMessage request;request.setMethod(QtSoapQName("GetWeather", "http://ws.cdyne.com/WeatherWS/"));// 添加參數request.addMethodArgument("CityName", "", "New York");request.addMethodArgument("State", "", "NY");// 創建 SOAP 傳輸QtSoapHttpTransport transport;transport.setHost("wsf.cdyne.com");transport.setAction("http://ws.cdyne.com/WeatherWS/GetWeather");// 發送請求transport.submitRequest(request, "/WeatherWS/Weather.asmx");// 等待響應while (!transport.isFinished()) {QCoreApplication::processEvents();}// 處理響應if (transport.error() == QtSoapHttpTransport::NoError) {const QtSoapMessage &response = transport.reply();if (!response.isFault()) {// 處理成功響應QtSoapType *result = response.returnValue().child("GetWeatherResult");if (result) {QtSoapType *weatherData = result->child("WeatherData");if (weatherData) {QtSoapType *temperature = weatherData->child("Temperature");if (temperature) {qDebug() << "Temperature:" << temperature->value().toString();}}}} else {// 處理錯誤qDebug() << "SOAP Fault:" << response.faultString().value().toString();}} else {// 處理傳輸錯誤qDebug() << "Transport error:" << transport.errorString();}return a.exec();
}

三、RESTful WebService 交互

1. REST 請求實現
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QEventLoop>class RestClient : public QObject {Q_OBJECT
public:explicit RestClient(QObject *parent = nullptr) : QObject(parent) {manager = new QNetworkAccessManager(this);}// GET 請求QJsonObject get(const QString &url, const QMap<QString, QString> &headers = {}) {QNetworkRequest request(QUrl(url));// 設置請求頭for (auto it = headers.begin(); it != headers.end(); ++it) {request.setRawHeader(it.key().toUtf8(), it.value().toUtf8());}QNetworkReply *reply = manager->get(request);QEventLoop loop;connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);loop.exec();QJsonObject result;if (reply->error() == QNetworkReply::NoError) {QByteArray data = reply->readAll();QJsonDocument doc = QJsonDocument::fromJson(data);if (doc.isObject()) {result = doc.object();}} else {result["error"] = reply->errorString();}reply->deleteLater();return result;}// POST 請求QJsonObject post(const QString &url, const QJsonObject &data, const QMap<QString, QString> &headers = {}) {QNetworkRequest request(QUrl(url));// 設置請求頭request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");for (auto it = headers.begin(); it != headers.end(); ++it) {request.setRawHeader(it.key().toUtf8(), it.value().toUtf8());}QByteArray jsonData = QJsonDocument(data).toJson();QNetworkReply *reply = manager->post(request, jsonData);QEventLoop loop;connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);loop.exec();QJsonObject result;if (reply->error() == QNetworkReply::NoError) {QByteArray responseData = reply->readAll();QJsonDocument doc = QJsonDocument::fromJson(responseData);if (doc.isObject()) {result = doc.object();}} else {result["error"] = reply->errorString();}reply->deleteLater();return result;}private:QNetworkAccessManager *manager;
};
2. 處理 JSON 響應
void processJsonResponse() {RestClient client;QJsonObject response = client.get("https://api.example.com/data");if (response.contains("error")) {qDebug() << "Error:" << response["error"].toString();return;}// 處理成功響應if (response.contains("items") && response["items"].isArray()) {QJsonArray items = response["items"].toArray();for (const QJsonValue &item : items) {if (item.isObject()) {QJsonObject obj = item.toObject();qDebug() << "Name:" << obj["name"].toString();qDebug() << "ID:" << obj["id"].toInt();}}}
}

四、XML 數據處理

1. 使用 QXmlStreamReader 解析 XML
void parseXml(const QByteArray &xmlData) {QXmlStreamReader xml(xmlData);while (!xml.atEnd() && !xml.hasError()) {QXmlStreamReader::TokenType token = xml.readNext();if (token == QXmlStreamReader::StartElement) {if (xml.name() == "book") {// 處理書籍元素QString title, author;int year = 0;// 讀取書籍屬性QXmlStreamAttributes attributes = xml.attributes();if (attributes.hasAttribute("id")) {QString bookId = attributes.value("id").toString();qDebug() << "Book ID:" << bookId;}// 讀取書籍內容while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "book")) {if (xml.tokenType() == QXmlStreamReader::StartElement) {if (xml.name() == "title") {title = xml.readElementText();} else if (xml.name() == "author") {author = xml.readElementText();} else if (xml.name() == "year") {year = xml.readElementText().toInt();}}xml.readNext();}qDebug() << "Title:" << title;qDebug() << "Author:" << author;qDebug() << "Year:" << year;}}}if (xml.hasError()) {qDebug() << "XML parsing error:" << xml.errorString();}
}
2. 使用 QXmlStreamWriter 生成 XML
QByteArray generateXml() {QByteArray data;QXmlStreamWriter xml(&data);xml.setAutoFormatting(true);xml.writeStartDocument();xml.writeStartElement("library");// 添加第一本書xml.writeStartElement("book");xml.writeAttribute("id", "1");xml.writeTextElement("title", "C++ Primer");xml.writeTextElement("author", "Stanley Lippman");xml.writeTextElement("year", "2012");xml.writeEndElement(); // book// 添加第二本書xml.writeStartElement("book");xml.writeAttribute("id", "2");xml.writeTextElement("title", "Effective C++");xml.writeTextElement("author", "Scott Meyers");xml.writeTextElement("year", "2005");xml.writeEndElement(); // bookxml.writeEndElement(); // libraryxml.writeEndDocument();return data;
}

五、安全認證與授權

1. HTTP 基本認證
void httpBasicAuth(const QString &url, const QString &username, const QString &password) {QNetworkRequest request(QUrl(url));// 設置基本認證QString credentials = username + ":" + password;QByteArray encoded = credentials.toUtf8().toBase64();request.setRawHeader("Authorization", "Basic " + encoded);// 發送請求QNetworkAccessManager manager;QNetworkReply *reply = manager.get(request);// 處理響應// ...
}
2. OAuth2 認證
class OAuth2Client : public QObject {Q_OBJECT
public:explicit OAuth2Client(QObject *parent = nullptr) : QObject(parent) {manager = new QNetworkAccessManager(this);}void authenticate(const QString &authUrl, const QString &clientId, const QString &redirectUri, const QString &scope) {// 構建認證 URLQUrl url(authUrl);QUrlQuery query;query.addQueryItem("response_type", "code");query.addQueryItem("client_id", clientId);query.addQueryItem("redirect_uri", redirectUri);query.addQueryItem("scope", scope);url.setQuery(query);// 打開瀏覽器進行認證QDesktopServices::openUrl(url);// 等待用戶授權并重定向回應用// 實際應用中需要處理重定向 URL 并提取授權碼}void getAccessToken(const QString &tokenUrl, const QString &clientId, const QString &clientSecret, const QString &authCode, const QString &redirectUri) {QUrl url(tokenUrl);QNetworkRequest request(url);request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");QUrlQuery query;query.addQueryItem("grant_type", "authorization_code");query.addQueryItem("code", authCode);query.addQueryItem("client_id", clientId);query.addQueryItem("client_secret", clientSecret);query.addQueryItem("redirect_uri", redirectUri);QByteArray postData = query.toString(QUrl::FullyEncoded).toUtf8();QNetworkReply *reply = manager->post(request, postData);connect(reply, &QNetworkReply::finished, this, [this, reply]() {if (reply->error() == QNetworkReply::NoError) {QByteArray data = reply->readAll();QJsonDocument doc = QJsonDocument::fromJson(data);if (doc.isObject()) {QJsonObject obj = doc.object();if (obj.contains("access_token")) {accessToken = obj["access_token"].toString();emit accessTokenReceived(accessToken);}}} else {emit error(reply->errorString());}reply->deleteLater();});}signals:void accessTokenReceived(const QString &token);void error(const QString &message);private:QNetworkAccessManager *manager;QString accessToken;
};

六、異步請求處理

1. 使用信號槽處理異步請求
class AsyncWebServiceClient : public QObject {Q_OBJECT
public:explicit AsyncWebServiceClient(QObject *parent = nullptr) : QObject(parent) {manager = new QNetworkAccessManager(this);}void makeRequest(const QString &url) {QNetworkRequest request(QUrl(url));QNetworkReply *reply = manager->get(request);// 連接信號connect(reply, &QNetworkReply::finished, this, [this, reply]() {if (reply->error() == QNetworkReply::NoError) {QByteArray data = reply->readAll();emit requestSuccess(data);} else {emit requestError(reply->errorString());}reply->deleteLater();});}signals:void requestSuccess(const QByteArray &data);void requestError(const QString &error);private:QNetworkAccessManager *manager;
};
2. 使用 QFuture 和 QtConcurrent
#include <QtConcurrent>QFuture<QByteArray> makeAsyncRequest(const QString &url) {return QtConcurrent::run([url]() {QNetworkAccessManager manager;QNetworkRequest request(QUrl(url));QNetworkReply *reply = manager.get(request);// 等待請求完成QEventLoop loop;QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);loop.exec();QByteArray data;if (reply->error() == QNetworkReply::NoError) {data = reply->readAll();} else {qDebug() << "Request error:" << reply->errorString();}reply->deleteLater();return data;});
}// 使用示例
void useAsyncRequest() {QFuture<QByteArray> future = makeAsyncRequest("https://api.example.com/data");// 可以繼續執行其他代碼...// 等待結果future.waitForFinished();QByteArray result = future.result();// 處理結果// ...
}

七、性能優化與最佳實踐

1. 連接池管理
class WebServiceConnectionPool : public QObject {Q_OBJECT
public:explicit WebServiceConnectionPool(int maxConnections = 5, QObject *parent = nullptr): QObject(parent), m_maxConnections(maxConnections) {}QNetworkAccessManager* acquireConnection() {// 從池中獲取可用連接if (!m_availableConnections.isEmpty()) {return m_availableConnections.takeFirst();}// 如果沒有可用連接且未達到最大連接數,則創建新連接if (m_activeConnections.size() < m_maxConnections) {QNetworkAccessManager *manager = new QNetworkAccessManager(this);m_activeConnections.append(manager);return manager;}// 達到最大連接數,等待連接釋放return nullptr;  // 實際實現中應該等待信號}void releaseConnection(QNetworkAccessManager *manager) {// 將連接返回到池中m_activeConnections.removeAll(manager);m_availableConnections.append(manager);}private:int m_maxConnections;QList<QNetworkAccessManager*> m_availableConnections;QList<QNetworkAccessManager*> m_activeConnections;
};
2. 數據緩存策略
class WebServiceCache : public QObject {Q_OBJECT
public:explicit WebServiceCache(int maxSize = 100, QObject *parent = nullptr): QObject(parent), m_maxSize(maxSize) {}bool hasData(const QString &key) const {return m_cache.contains(key);}QByteArray getData(const QString &key) const {return m_cache.value(key);}void setData(const QString &key, const QByteArray &data) {// 如果緩存已滿,移除最舊的項if (m_cache.size() >= m_maxSize) {m_cache.remove(m_cache.keys().first());}m_cache[key] = data;}private:int m_maxSize;QCache<QString, QByteArray> m_cache;
};

八、總結

Qt 提供了豐富的工具和類庫來實現與 WebService 的交互,無論是基于 SOAP 協議的傳統 WebService,還是現代的 RESTful API。通過合理使用 QNetworkAccessManager、XML 解析器和 JSON 處理類,開發者可以輕松構建高效、穩定的 WebService 客戶端。

在實際開發中,還需要考慮安全性、性能優化、錯誤處理等方面的問題。合理應用認證機制、連接池管理和數據緩存策略,可以顯著提升應用的性能和用戶體驗。通過本文介紹的技術和最佳實踐,開發者可以更好地實現 Qt 與 WebService 的交互,構建出高質量的跨平臺應用。

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

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

相關文章

LLM 模型部署難題的技術突破:從輕量化到分布式推理的全棧解決方案

大語言模型(LLM)的部署一直是工業落地的核心挑戰。動輒百億甚至萬億參數的模型規模,對硬件資源、推理速度和系統穩定性提出了嚴苛要求。本文將系統剖析 LLM 部署中的關鍵技術瓶頸,從模型壓縮、推理加速到分布式架構設計,提供可落地的工程化解決方案,并附具體實現代碼。 …

理解訓練深度前饋神經網絡的困難—— 解鎖深度學習的關鍵鑰匙

2010年&#xff0c;深度學習先驅 Xavier Glorot 和 Yoshua Bengio 發表了這篇里程碑式的論文。它精準地診斷了當時阻礙深度神經網絡發展的核心頑疾——**梯度消失/爆炸問題**&#xff0c;并開出了革命性的“藥方”&#xff1a;**Xavier/Glorot 初始化**。這篇論文掃清了訓練深度…

Objective-c 初階——異常處理(try-catch)

一、try/catch/throw/finally 執行順序 void doSomething() {NSAutoreleasePool *pool [[NSAutoreleasePool alloc] init];try {// 這一步拋異常[self riskyMethod]; } catch (NSException *e) {throw; // 把異常繼續往上拋} finally {// ? 注意&#xff1a;這里的 finally…

計算機網絡:(十二)傳輸層(上)運輸層協議概述

計算機網絡&#xff1a;&#xff08;十一&#xff09;多協議標記交換 MPLS前言一、運輸層的作用二、基于端口的復用和分用功能三、屏蔽作用四、可靠信道與不可靠信道五、運輸層的兩個主要協議前言 前面我們講解了計算機網絡中網絡層的相關知識&#xff0c;包括網絡層轉發分組的…

一場關于電商零售增長破局的深圳探索

“電商AI&#xff0c;不再是選擇題”2025年&#xff0c;電商行業正面臨流量成本攀升、用戶留存率下降、供應鏈協同效率低等核心困境&#xff0c;傳統數字化工具已難以滿足精細化運營需求。在此背景下&#xff0c;百度智能云正加速布局電商領域&#xff0c;為零售企業提供從基礎…

當非洲愛上“中國制造”:如何贏在起跑線

非洲大陸的消費浪潮正以前所未有的速度奔涌。2025年前五個月&#xff0c;中非貿易額同比暴漲12.4%&#xff0c;創下歷史新高。在這片擁有14億人口的土地上&#xff0c;60%是30歲以下的年輕人&#xff0c;城鎮化浪潮席卷、中產階級快速崛起&#xff0c;從家電、汽車到建材、電子…

vLLM(3)vllm在線啟動集成openweb-ui

文章目錄**步驟 1: 啟動 vLLM 服務****方式 1: 直接命令行啟動****方式 2: Docker 啟動****步驟 2: 配置 Open WebUI 連接 vLLM****方法 1: 修改 Open WebUI 環境變量****方法 2: 通過 docker-compose.yml 部署****步驟 3: 在 Open WebUI 中添加模型****驗證是否成功****常見問…

Python----大模型(基于Agent的私人AI助理項目)

開發一個智能的問答系統&#xff0c;該系統支持用戶聊天&#xff0c;傳輸文件。通過自然語言處理技術&#xff0c;機器人能夠理解用戶的意圖。機器人將利用互聯網搜索引擎來補充信息&#xff0c;確保用戶能夠獲得全面且準確的回答。 一、web ui界面 我們采用gradio來編寫的ui界…

Python爬蟲實戰:研究scrapely庫相關技術構建電商數據提取系統

1. 引言 在當今數字化時代,網絡上蘊含著海量的有價值信息。如何從這些非結構化的網頁中自動提取出結構化的數據,成為了數據挖掘和信息檢索領域的重要研究課題。網絡爬蟲作為一種自動獲取網頁內容的技術,被廣泛應用于信息收集、數據分析等領域。然而,網頁結構的多樣性和復雜…

Orange的運維學習日記--18.Linux sshd安全實踐

Orange的運維學習日記–18.Linux sshd安全實踐 文章目錄Orange的運維學習日記--18.Linux sshd安全實踐場景模擬sshd配置需求&#xff1a;參數表格&#xff1a;MOTD警告定期備份SSH密鑰與配置登錄防護&#xff1a;fail2ban測試與日志場景模擬 你是某金融科技公司的Linux運維工程…

聚觀早報 | 德賽電池自主研發主動安全AI電芯;華為首展線下昇騰384超節點;蔚來純電小車螢火蟲已交付一萬輛

聚觀早報每日整理最值得關注的行業重點事件&#xff0c;幫助大家及時了解最新行業動態&#xff0c;每日讀報&#xff0c;就讀聚觀365資訊簡報。整理丨肖羽7月28日消息德賽電池自主研發主動安全AI電芯華為首展線下昇騰384超節點蔚來純電小車螢火蟲已交付一萬輛京東已成立智能機器…

python可視化:按序號展示社團星級分布 - 熱力圖樣式

目錄 關鍵代碼&#xff1a; 運行結果&#xff1a; 關鍵代碼&#xff1a; # 4. 按序號展示社團星級分布 - 熱力圖樣式 plt.subplot(2, 2, 4) # 創建星級映射為數值 star_mapping {五星:4, 四星:3, 三星:2, 星級入圍:1} star_values df[答辯結果].map(star_mapping) plt.s…

智能家居平臺服務端安裝教程——東方仙盟部署

1. 準備工作 登錄阿里云服務器&#xff1a;使用 SSH 工具&#xff08;如 ssh 命令&#xff09;登錄到你的阿里云 Linux 服務器。確保服務器已安裝并能正常運行&#xff0c;且網絡連接正常。更新系統軟件包&#xff1a;執行以下命令更新系統軟件包到最新版本。 bash sudo apt …

360環視技術推薦的硬件平臺:支持多攝像頭與三屏異顯的理想選擇

在智能硬件不斷升級的今天&#xff0c;360環視技術早已不只是豪華車型的專屬。通過布置多路攝像頭&#xff0c;并將其圖像進行融合處理&#xff0c;360環視可以為系統提供車輛或設備周圍的完整視野。 它不僅能夠消除盲區&#xff0c;還能通過AI識別實現物體檢測、避障判斷、自動…

FFmpeg:因碼流采集與封裝不同步導致錄制出來的MP4文件會出現黑屏、綠屏的問題

項目要求實時播放視頻&#xff0c;并且需要支持播放中途可以錄制視頻。但是錄制出來的文件會黑屏&#xff0c;過一段時間后正常顯示。即&#xff1a;碼流采集—>播放—>&#xff08;一段時間后&#xff09;錄制MP4&#xff0c;黑屏出現的時間就在采集到錄制之前。黑屏現象…

C 語言與 C++、Java、Python 等編程語言的區別

C 語言與 C、Java、Python 等編程語言在設計理念、特性和應用場景上存在顯著差異&#xff0c;以下從核心區別、特性對比和適用場景三個維度詳細解析&#xff1a;一、C 語言與 C 的核心區別C 是在 C 語言基礎上發展而來&#xff08;最初名為 “C with Classes”&#xff09;&…

Apache Ignite 的分布式鎖Distributed Locks的介紹

以下這段內容是關于 Apache Ignite 的分布式鎖&#xff08;Distributed Locks&#xff09; 的介紹。這是一個非常重要的功能&#xff0c;用于在分布式系統中協調多個節點對共享資源的并發訪問。 下面我們來一步步深入理解它。&#x1f3af; 一、一句話理解&#xff1a;什么是 I…

第十二天:C++ 標準庫函數分類總結

C 標準庫函數分類總結 數學函數&#xff08;<cmath>&#xff09; 基本運算函數 abs(x)&#xff1a;返回整數或浮點數的絕對值。int a abs(-5); // 返回 5fabs(x)&#xff1a;返回浮點數的絕對值。double b fabs(-3.14); // 返回 3.14fmod(x, y)&#xff1a;計算 x 除以…

Unity Standard Shader 解析(四)之ForwardAdd(簡化版)

一、ForwardAdd// Additive forward pass (one light per pass)Pass{Name "FORWARD_DELTA"Tags { "LightMode" "ForwardAdd" }Blend [_SrcBlend] OneFog { Color (0,0,0,0) } // in additive pass fog should be blackZWrite OffZTest LEqualC…

第十九周-文檔數據庫MongoDB、消息隊列和微服務

1. 完成redis單機安裝&#xff0c;哨兵模式安裝&#xff0c;主從安裝&#xff0c;集群安裝單機安裝#安裝依賴包 [rootcentos8~]#yum -y install gcc make jemalloc-devel #如果支持systemd需要安裝下面包 [rootubuntu2204 ~]#apt update && apt -y install make gcc li…