C++ - 仿 RabbitMQ 實現消息隊列--服務端核心模塊實現(一)

目錄

日志打印工具

實用 Helper 工具

sqlite 基礎操作類

?字符串操作類

?UUID 生成器類

?文件基礎操作

文件是否存在判斷

文件大小獲取

讀文件

寫文件

文件重命名

文件創建/刪除

?父級目錄的獲取

目錄創建/刪除

附錄(完整代碼)


日志打印工具

????????為了便于編寫項目中能夠快速定位程序的錯誤位置,因此編寫一個日志輸出宏工具,進行簡單的日志打印。

  • 定義DEBUG,INFO,ERROR三個日志等級。
  • 日志格式:[日志等級][時間][文件][行號]? ? 日志信息。
#pragma once#include <iostream>
#include <ctime>
#include <string>namespace jiuqi
{
#define DEBUG_LEVEL 0
#define INFO_LEVEL 1
#define ERROR_LEVEL 2#define DEFAULT_LEVEL DEBUG_LEVEL#define LOG(level, fmt, ...)                                                                                \{                                                                                                         \if (level >= DEFAULT_LEVEL)                                                                           \{                                                                                                     \std::string level_str;                                                                            \if (level == DEBUG_LEVEL)                                                                         \level_str = "DEBUG";                                                                          \else if (level == INFO_LEVEL)                                                                     \level_str = "INFO";                                                                           \else                                                                                              \level_str = "ERROR";                                                                          \time_t t = time(nullptr);                                                                         \struct tm *tm = localtime(&t);                                                                    \char time[32];                                                                                    \strftime(time, 31, "%H:%M:%S", tm);                                                               \printf("[%s][%s][%s:%d]\t" fmt "\n", level_str.c_str(), time,  __FILE__, __LINE__, ##__VA_ARGS__);\}                                                                                                     \}#define DEBUG(fmt, ...) LOG(DEBUG_LEVEL, fmt, ##__VA_ARGS__)
#define INFO(fmt, ...) LOG(INFO_LEVEL, fmt, ##__VA_ARGS__)
#define ERROR(fmt, ...) LOG(ERROR_LEVEL, fmt, ##__VA_ARGS__)
}

實用 Helper 工具

????????Helper 工具類中要完成的是項目中需要的一些輔助零碎的功能代碼實現,其中包括文
件的基礎操作,字符串的額外操作等在項目中用到的零碎功能。

sqlite 基礎操作類

? ? ? ? 使用我們之前demo中編寫過的sqlite類即可,將輸出替換為日志打印。

    class SqliteHelper{public:typedef int (*sqliteCallback)(void *, int, char **, char **);SqliteHelper(const std::string &dbfile): _dbfile(dbfile), _handler(nullptr) {}bool open(int safe_level = SQLITE_OPEN_FULLMUTEX){int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level, nullptr);if (ret != SQLITE_OK){// std::cerr << "打開/創建數據庫失敗: " << sqlite3_errmsg(_handler) << std::endl;ERROR("%s:%s", "打開/創建數據庫失敗", sqlite3_errmsg(_handler));return false;}return true;}bool exec(const std::string &sql, sqliteCallback callback, void *arg){int ret = sqlite3_exec(_handler, sql.c_str(), callback, arg, nullptr);if (ret != SQLITE_OK){// std::cerr << sql << std::endl;// std::cerr << "執行語句失敗: " << sqlite3_errmsg(_handler) << std::endl;ERROR("%s\n%s:%s", sql.c_str(), "執行語句失敗: ", sqlite3_errmsg(_handler));return false;}return true;}void close(){if (_handler)sqlite3_close_v2(_handler);}private:std::string _dbfile;sqlite3 *_handler;};

?字符串操作類

? ? ? ? 這里先實現字符串分割功能,主要是用于后續消息類型與隊列類型,即綁定信息匹配的問題。

    class StrHelper{public:static size_t split(const std::string &str, const std::string &sep, std::vector<std::string> &result){size_t end = 0, start = 0;while (start < str.size()){end = str.find(sep, start);if (end == std::string::npos){result.push_back(str.substr(start));break;}if (end != start){result.push_back(str.substr(start, end - start));}start = end + sep.size();}return result.size();}};

說明:

  • 以sep作為分割符將str分割,結果存放在result中。
  • 返回分割子串的數量。
  • 注意,如果出現連續的分割符,我們必須跳過,即不允許插入空串。

?UUID 生成器類

????????UUID(Universally Unique Identifier), 也叫通用唯一識別碼,通常由 32 位 16 進制數字字符組成。

????????在這里,uuid 生成,我們采用生成 8 個隨機數字,加上 8 字節序號,共 16 字節數組生成 32 位 16 進制字符的組合形式來確保全局唯一的同時能夠根據序號來分辨數據。

? ? ? ? 為了獲得隨機數與穩定遞增的序號(需支持高并發),我們介紹一下幾個對象:

  • 隨機數:
    • std::random_device對象:生成機器隨機數,真隨機數,但是效率較低。

    • std::mt19937_64對象:64位梅森旋轉算法(Mersenne Twister)生成偽隨機數,可以使用std::random_device對象生成的隨機數作為種子。

    • std::uniform_int_distribution<int>對象:將隨機數引擎的輸出轉換為均勻分布的整數。

  • 序號:
    • 使用size_t的原子計數器,使用fetch_add接口可以獲得穩定遞增的序號。
    class UUIDHelper{public:static std::string uuid(){std::random_device rd;std::mt19937_64 gernator(rd());std::uniform_int_distribution<int> distribution(0, 255);std::stringstream ss;for (int i = 1; i <= 8; i++){ss << std::setw(2) << std::setfill('0') << std::hex << distribution(gernator);if (i % 2 == 0)ss << '-';}static std::atomic<size_t> sep(1);size_t num = sep.fetch_add(1);for (int i = 7; i >= 0; i--){ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);if (i == 4)ss << '-';}return ss.str();}};

?文件基礎操作

? ? ? ? 我們將提供一系列文件操作,每個功能實現靜態和非靜態操作兩種。

文件是否存在判斷

        bool exists(){struct stat st;return (stat(_filename.c_str(), &st) == 0);}static bool exists(const std::string &filename){struct stat st;return (stat(filename.c_str(), &st) == 0);}

????????使用stat接口可跨平臺。

文件大小獲取

        size_t size(){struct stat st;int ret = stat(_filename.c_str(), &st);if (ret < 0)return 0;return st.st_size;}static size_t size(const std::string &filename){struct stat st;int ret = stat(filename.c_str(), &st);if (ret < 0)return 0;return st.st_size;}

? ? ? ? 同樣使用stat接口,文件大小會被存放在結構體st中。

讀文件

        bool read(std::string &body){size_t fsize = this->size();return read(body, 0, fsize);}bool read(std::string &body, size_t offset, size_t len){// 打開文件std::ifstream ifs(_filename, std::ios::binary | std::ios::in);if (!ifs.is_open()){ERROR("%s:文件打開失敗", _filename.c_str());return false;}// 移動文件讀取位置ifs.seekg(offset, std::ios::beg);// 讀取文件body.resize(len);ifs.read(&body[0], len);if (!ifs.good()){ERROR("%s:文件讀取失敗", _filename.c_str());ifs.close();return false;}// 關閉文件返回ifs.close();return true;}static bool read(const std::string &filename, std::string &body){size_t fsize = size(filename);return read(filename, body, 0, fsize);}static bool read(const std::string &filename, std::string &body, size_t offset, size_t len){// 打開文件std::ifstream ifs(filename, std::ios::binary | std::ios::in);if (!ifs.is_open()){ERROR("%s:文件打開失敗", filename.c_str());return false;}// 移動文件讀取位置ifs.seekg(offset, std::ios::beg);// 讀取文件body.resize(len);ifs.read(&body[0], len);if (!ifs.good()){ERROR("%s:文件讀取失敗", filename.c_str());ifs.close();return false;}// 關閉文件返回ifs.close();return true;}

? ? ? ? 我們提供讀取文件全部內容與讀取文件特定位置特定長度內容的接口,有兩點需要注意:

  1. 每次讀取需要把讀取緩沖區(即body)resize,否則會導致讀取失敗。
  2. ifstream對象的read接口第一個參數是char*類型的,不能使用string對象的c_str接口(因為返回的是const char*),解決辦法是傳入body第一個字符的地址。

寫文件

        bool write(const std::string &body){size_t fsize = this->size();return write(body.c_str(), fsize, body.size());}bool write(const char *body, size_t offset, size_t len){// 打開文件std::fstream fs(_filename, std::ios::binary | std::ios::out | std::ios::in);if (!fs.is_open()){ERROR("%s:文件打開失敗", _filename.c_str());return false;}// 移動文件寫入位置fs.seekp(offset, std::ios::beg);// 寫入文件fs.write(body, len);if (!fs.good()){ERROR("%s:文件讀取失敗", _filename.c_str());fs.close();return false;}fs.close();return true;}static bool write(const std::string &filename, const std::string &body){size_t fsize = size(filename);return write(filename, body.c_str(), fsize, body.size());}static bool write(const std::string &filename, const char *body, size_t offset, size_t len){// 打開文件std::fstream fs(filename, std::ios::binary | std::ios::out | std::ios::in);if (!fs.is_open()){ERROR("%s:文件打開失敗", filename.c_str());return false;}// 移動文件寫入位置fs.seekp(offset, std::ios::beg);// 寫入文件fs.write(body, len);if (!fs.good()){ERROR("%s:文件讀取失敗", filename.c_str());fs.close();return false;}fs.close();return true;}

? ? ? ? ?這里實現了追加寫入與在特定位置寫入的功能,但是在特定位置寫入會覆蓋原本的內容,暫時未實現真正的插入功能。

? ? ? ? 需要注意,因為要移動文件寫位置,必須以讀寫方式打開文件。

文件重命名

        bool rename(const std::string new_name){return ::rename(_filename.c_str(), new_name.c_str());}static bool rename(const std::string old_name, const std::string new_name){return ::rename(old_name.c_str(), new_name.c_str());}

? ? ? ? 使用庫中的rename函數即可,一定要前加兩個冒號,聲明作用域。

文件創建/刪除

        bool createFile(){return createFile(_filename);}static bool createFile(const std::string &filename){// 打開文件并立即關閉,創建空文件std::ofstream ofs(filename, std::ios::out);if (!ofs.is_open()){ERROR("%s:文件創建失敗", filename.c_str());return false;}ofs.close();return true;}bool removeFile(){return removeFile(_filename);}static bool removeFile(const std::string &filename){return (::remove(filename.c_str()) == 0);}
  1. 文件創建:ofstrea的out打開模式:如果文件不存在就會創建。
  2. 文件刪除,調用庫中的remove接口即可。

?父級目錄的獲取

        std::string parentDirectory(){return parentDirectory(_filename);}static std::string parentDirectory(const std::string &filename){size_t pos = filename.find_last_of("/\\");if (pos == std::string::npos)return ".";std::string path = filename.substr(0, pos);return path;}

? ? ? ? 尋找最后一個文件目錄分割符即可,找不到就返回當前目錄。

目錄創建/刪除

        bool createDirectory(){return createDirectory(parentDirectory(_filename));}static bool createDirectory(const std::string &path){size_t start = 0, end = 0;while (start < path.size()){end = path.find_first_of("/\\", start);if (end == std::string::npos){
#ifdef _WIN32int ret = _mkdir(path.c_str());
#elseint ret = mkdir(path.c_str(), 0775);
#endifif (ret != 0 && errno != EEXIST){ERROR("%s:目錄創建失敗,錯誤碼: %d", path.c_str(), errno);return false;}break;}if (end == start){start += 1;continue;}std::string subpath = path.substr(0, end);if (exists(path)){start = end + 1;continue;}if (!subpath.empty()){
#ifdef _WIN32int ret = _mkdir(subpath.c_str());
#elseint ret = mkdir(subpath.c_str(), 0775);
#endifif (ret != 0 && errno != EEXIST){ERROR("%s:目錄創建失敗,錯誤碼: %d", subpath.c_str(), errno);return false;}}start = end + 1;}return true;}bool removeDirectory(){return removeDirectory(parentDirectory(_filename));}static bool removeDirectory(const std::string &path){std::string cmd = "rm -rf " + path;return (system(cmd.c_str()) != -1);}
  1. 目錄的創建:需要先創建父級目錄才可以創建當前目錄,注意如果遇到連續的文件目錄分割符需要跳過。
  2. 目錄的刪除:調用系統命令即可。

附錄(完整代碼)

#pragma once#include <sqlite3.h>
#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <sstream>
#include <fstream>
#include <atomic>
#include <sys/stat.h>
#include <iomanip>#ifdef _WIN32#include <direct.h>
#endif#include "log.hpp"namespace jiuqi
{class SqliteHelper{public:typedef int (*sqliteCallback)(void *, int, char **, char **);SqliteHelper(const std::string &dbfile): _dbfile(dbfile), _handler(nullptr) {}bool open(int safe_level = SQLITE_OPEN_FULLMUTEX){int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level, nullptr);if (ret != SQLITE_OK){// std::cerr << "打開/創建數據庫失敗: " << sqlite3_errmsg(_handler) << std::endl;ERROR("%s:%s", "打開/創建數據庫失敗", sqlite3_errmsg(_handler));return false;}return true;}bool exec(const std::string &sql, sqliteCallback callback, void *arg){int ret = sqlite3_exec(_handler, sql.c_str(), callback, arg, nullptr);if (ret != SQLITE_OK){// std::cerr << sql << std::endl;// std::cerr << "執行語句失敗: " << sqlite3_errmsg(_handler) << std::endl;ERROR("%s\n%s:%s", sql.c_str(), "執行語句失敗: ", sqlite3_errmsg(_handler));return false;}return true;}void close(){if (_handler)sqlite3_close_v2(_handler);}private:std::string _dbfile;sqlite3 *_handler;};class StrHelper{public:static size_t split(const std::string &str, const std::string &sep, std::vector<std::string> &result){size_t end = 0, start = 0;while (start < str.size()){end = str.find(sep, start);if (end == std::string::npos){result.push_back(str.substr(start));break;}if (end != start){result.push_back(str.substr(start, end - start));}start = end + sep.size();}return result.size();}};class UUIDHelper{public:static std::string uuid(){std::random_device rd;std::mt19937_64 gernator(rd());std::uniform_int_distribution<int> distribution(0, 255);std::stringstream ss;for (int i = 1; i <= 8; i++){ss << std::setw(2) << std::setfill('0') << std::hex << distribution(gernator);if (i % 2 == 0)ss << '-';}static std::atomic<size_t> sep(1);size_t num = sep.fetch_add(1);for (int i = 7; i >= 0; i--){ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);if (i == 4)ss << '-';}return ss.str();}};class FileHelper{public:FileHelper(const std::string &filename) : _filename(filename) {}bool exists(){struct stat st;return (stat(_filename.c_str(), &st) == 0);}static bool exists(const std::string &filename){struct stat st;return (stat(filename.c_str(), &st) == 0);}size_t size(){struct stat st;int ret = stat(_filename.c_str(), &st);if (ret < 0)return 0;return st.st_size;}static size_t size(const std::string &filename){struct stat st;int ret = stat(filename.c_str(), &st);if (ret < 0)return 0;return st.st_size;}bool read(std::string &body){size_t fsize = this->size();return read(body, 0, fsize);}bool read(std::string &body, size_t offset, size_t len){// 打開文件std::ifstream ifs(_filename, std::ios::binary | std::ios::in);if (!ifs.is_open()){ERROR("%s:文件打開失敗", _filename.c_str());return false;}// 移動文件讀取位置ifs.seekg(offset, std::ios::beg);// 讀取文件body.resize(len);ifs.read(&body[0], len);if (!ifs.good()){ERROR("%s:文件讀取失敗", _filename.c_str());ifs.close();return false;}// 關閉文件返回ifs.close();return true;}static bool read(const std::string &filename, std::string &body){size_t fsize = size(filename);return read(filename, body, 0, fsize);}static bool read(const std::string &filename, std::string &body, size_t offset, size_t len){// 打開文件std::ifstream ifs(filename, std::ios::binary | std::ios::in);if (!ifs.is_open()){ERROR("%s:文件打開失敗", filename.c_str());return false;}// 移動文件讀取位置ifs.seekg(offset, std::ios::beg);// 讀取文件body.resize(len);ifs.read(&body[0], len);if (!ifs.good()){ERROR("%s:文件讀取失敗", filename.c_str());ifs.close();return false;}// 關閉文件返回ifs.close();return true;}bool write(const std::string &body){size_t fsize = this->size();return write(body.c_str(), fsize, body.size());}bool write(const char *body, size_t offset, size_t len){// 打開文件std::fstream fs(_filename, std::ios::binary | std::ios::out | std::ios::in);if (!fs.is_open()){ERROR("%s:文件打開失敗", _filename.c_str());return false;}// 移動文件寫入位置fs.seekp(offset, std::ios::beg);// 寫入文件fs.write(body, len);if (!fs.good()){ERROR("%s:文件讀取失敗", _filename.c_str());fs.close();return false;}fs.close();return true;}static bool write(const std::string &filename, const std::string &body){size_t fsize = size(filename);return write(filename, body.c_str(), fsize, body.size());}static bool write(const std::string &filename, const char *body, size_t offset, size_t len){// 打開文件std::fstream fs(filename, std::ios::binary | std::ios::out | std::ios::in);if (!fs.is_open()){ERROR("%s:文件打開失敗", filename.c_str());return false;}// 移動文件寫入位置fs.seekp(offset, std::ios::beg);// 寫入文件fs.write(body, len);if (!fs.good()){ERROR("%s:文件讀取失敗", filename.c_str());fs.close();return false;}fs.close();return true;}bool rename(const std::string new_name){return ::rename(_filename.c_str(), new_name.c_str());}static bool rename(const std::string old_name, const std::string new_name){return ::rename(old_name.c_str(), new_name.c_str());}bool createFile(){return createFile(_filename);}static bool createFile(const std::string &filename){// 打開文件并立即關閉,創建空文件std::ofstream ofs(filename, std::ios::out);if (!ofs.is_open()){ERROR("%s:文件創建失敗", filename.c_str());return false;}ofs.close();return true;}bool removeFile(){return removeFile(_filename);}static bool removeFile(const std::string &filename){return (::remove(filename.c_str()) == 0);}bool createDirectory(){return createDirectory(parentDirectory(_filename));}static bool createDirectory(const std::string &path){size_t start = 0, end = 0;while (start < path.size()){end = path.find_first_of("/\\", start);if (end == std::string::npos){
#ifdef _WIN32int ret = _mkdir(path.c_str());
#elseint ret = mkdir(path.c_str(), 0775);
#endifif (ret != 0 && errno != EEXIST){ERROR("%s:目錄創建失敗,錯誤碼: %d", path.c_str(), errno);return false;}break;}if (end == start){start += 1;continue;}std::string subpath = path.substr(0, end);if (exists(path)){start = end + 1;continue;}if (!subpath.empty()){
#ifdef _WIN32int ret = _mkdir(subpath.c_str());
#elseint ret = mkdir(subpath.c_str(), 0775);
#endifif (ret != 0 && errno != EEXIST){ERROR("%s:目錄創建失敗,錯誤碼: %d", subpath.c_str(), errno);return false;}}start = end + 1;}return true;}bool removeDirectory(){return removeDirectory(parentDirectory(_filename));}static bool removeDirectory(const std::string &path){std::string cmd = "rm -rf " + path;return (system(cmd.c_str()) != -1);}std::string parentDirectory(){return parentDirectory(_filename);}static std::string parentDirectory(const std::string &filename){size_t pos = filename.find_last_of("/\\");if (pos == std::string::npos)return ".";std::string path = filename.substr(0, pos);return path;}private:std::string _filename;};
}

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

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

相關文章

C語言:第07天筆記

C語言&#xff1a;第07天筆記 內容提要 循環結構 break與continue 綜合案例《猜拳游戲》數組 數組的概念一維數組流程控制 break與continue break 功能&#xff1a; ① 用在switch中&#xff0c;用來跳出switch中的case語句&#xff1b;如果case沒有break&#xff0c;可能會產生…

qt 中英文翻譯 如何配置和使用

qt 中英文翻譯 如何配置和使用 1. 在.pro文件中添加TRANSLATIONS 在你的 .pro 文件&#xff08;比如 HYAC_AAF_HOST.pro&#xff09;中添加&#xff1a; TRANSLATIONS \ zh\_CN.ts en\_US.ts這會告訴Qt項目你要支持中文和英文。 2. 提取可翻譯文本&#xff08;生成ts文件&#…

Leetcode 710. 黑名單中的隨機數

1.題目基本信息 1.1.題目描述 給定一個整數 n 和一個 無重復 黑名單整數數組 blacklist 。設計一種算法&#xff0c;從 [0, n - 1] 范圍內的任意整數中選取一個 未加入 黑名單 blacklist 的整數。任何在上述范圍內且不在黑名單 blacklist 中的整數都應該有 同等的可能性 被返…

RxJava 全解析:從原理到 Android 實戰

在 Android 開發中&#xff0c;異步任務處理是繞不開的核心場景 —— 網絡請求、數據庫操作、文件讀寫等都需要在后臺執行&#xff0c;而結果需回調到主線程更新 UI。傳統的 “HandlerThread” 或 AsyncTask 不僅代碼冗余&#xff0c;還容易陷入 “回調地獄”&#xff08;嵌套回…

OpenCV 官翻7 - 對象檢測

文章目錄ArUco 標記檢測標記與字典標記物創建標記檢測姿態估計選擇字典預定義字典自動生成字典手動定義字典檢測器參數閾值處理adaptiveThreshConstant輪廓過濾minMarkerPerimeterRate 與 maxMarkerPerimeterRatepolygonalApproxAccuracyRateminCornerDistanceRateminMarkerDis…

【Oracle】ORACLE OMF說明

ORACLE OMF (Oracle Managed Files) 是 Oracle 數據庫提供的一項自動化文件管理功能。它的核心目的是簡化數據庫管理員&#xff08;DBA&#xff09;對數據庫底層操作系統文件的管理工作。 以下是 OMF 的關鍵要點&#xff1a; 核心功能&#xff1a;自動命名和定位文件 在創建數據…

408考研逐題詳解:2010年第35題——RIP協議

2010年第35題 某自治系統內采用 RIP 協議&#xff0c;若該自治系統內的路由器 R1 收到其鄰居路由器 R2 的距離矢量&#xff0c;距離矢量中包含信息 <net1, 16>&#xff0c;則能得出的結論是&#xff08; &#xff09; A. R2 可以經過 R1 到達 net1&#xff0c;跳數為17 …

http與https的主要區別是什么?

什么是HTTP&#xff1f; HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本傳輸協議&#xff09;是互聯網上應用最為廣泛的一種網絡協議。它構成了Web數據通信的基礎&#xff0c;并定義了客戶端和服務器之間如何請求和傳遞網頁信息。當您在瀏覽器中輸入一個網址時…

STC89C52系列單片機簡介

STC89C52系列單片機是由中國宏晶科技&#xff08;STC&#xff09;推出的一款新一代增強型8051內核單片機。它不僅繼承了傳統8051指令系統的兼容性&#xff0c;還在性能、功耗、抗干擾能力以及性價比方面進行了全面提升&#xff0c;廣泛應用于各類嵌入式控制場景&#xff0c;如工…

基于 Docker 環境的 JupyterHub 詳細部署手冊

本文詳細介紹基于Docker Compose的單機版JupyterHub部署方案&#xff0c;通過容器化技術實現多用戶Notebook環境的快速搭建。方案采用官方JupyterHub鏡像&#xff0c;配置11個端口映射&#xff08;18000-18010&#xff09;支持用戶并發&#xff0c;通過數據卷掛載&#xff08;.…

常見的萬能密碼

目錄 1. 通用SQL注入 2. 登錄繞過 3. 密碼重置 1. 通用SQL注入 or 11-- " or 11-- or aa " or "a""a or 11# " or 11# or 11/* " or 11/* or 11 " or "1""1 2. 登錄繞過 admin-- admin or 11-- admin or aa …

04訓練windows電腦低算力顯卡如何部署pytorch實現GPU加速

大多數人用的電腦的顯卡配置可能沒有那么強,也就是說,我們很難享受到最新版本pytorch給我們帶來的模型訓練的速度和效率,為此,我們需要想辦法在現有顯卡情況下部署應用pytorch。 筆者有一臺電腦,顯卡算力很低,那么以該電腦為例,為大家介紹如何部署應用pytorch功能。 1…

PPT科研畫圖插件

PPT科研畫圖插件 iSlide- 讓PPT設計簡單起來 | PPT模板下載平臺iSlide - 簡單&#xff0c;好用的PPT插件&#xff01;擁有30萬 原創可商用PPT模板&#xff0c;PPT主題素材&#xff0c;PPT案例&#xff0c;PPT圖表&#xff0c;PPT圖示&#xff0c;PPT圖標&#xff0c;PPT插圖和8…

CSS實現背景圖片漸變透明

復合寫法background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #FFF 82.5%),url(https://example.com/image.jpg) center / cover no-repeat;參數說明&#xff1a;linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #FFF 82.5%)創建從下至上的垂直漸變&#xff…

基于pyside6的通用機器人遙控控制界面

1. 前言 這兩天需要幫一個朋友做一個簡單的遙控控制界面&#xff0c;用于控制一臺復合機器人(萬向輪底盤機械臂旋轉云臺)&#xff0c;在這里分享一下 2. 開發框架 由于朋友那邊的控制接口都是使用python來寫的&#xff0c;所以我這里也使用py來完成這個遙控界面的開發。但其…

【iOS】ZARA仿寫

【iOS】ZARA仿寫 文章目錄【iOS】ZARA仿寫前言首頁發現我的對姓名的更改總結前言 暑假第一個的任務仿寫ZARA 雖然不是特別難卻有很多小細節需要注意 首頁 點進程序出現的就是整個項目最主要的一個點&#xff0c;即首頁的無限輪播圖&#xff0c;不管是自動輪播還是手動滑動&a…

Kubernetes Pod 調度基礎

一、Replication Controller 和 ReplicaSet1、Replication ControllerReplication Controller&#xff08;復制控制器&#xff0c;RC&#xff09;RC 用來確保 Pod 副本數達到期望值&#xff0c;這樣可以確保一個或多個同類 Pod 總是可用的。如果存在的 Pod 數量大于設定的值&am…

菜鳥的C#學習(二)

文章目錄一、類的訪問1、普通類繼承抽象類2、普通類繼承抽象類&#xff0c;抽象類繼承接口&#xff0c;三者聯系二、類中方法的訪問2.1 抽象方法和虛方法2.2 虛方法和普通方法**1. 調用機制****2. 方法重寫****3. 設計意圖****4. 性能差異****5. 語法對比表****總結&#xff1a…

04 51單片機之數碼管顯示

文章目錄1、前言2、數碼管3、單個數碼管引腳定義3-1、單個共陰極3-2、單個共陽極3-3、單個數碼管引腳定義4、四位一體數碼管引腳定義4-1、四位一體共陰極數碼管4-2、四位一體共陽極數碼管4-3、四位一體數碼管引腳定義5、數碼管原理圖6、C51數組&#xff08;補充知識點&#xff…

【LLM】OpenRouter調用Anthropic Claude上下文緩存處理

背景 在使用OpenRouter調用Anthropic Claude大模型時&#xff0c;部分模型支持上下文緩存功能。當緩存命中時&#xff0c;調用成本會顯著降低。雖然像DeepSeek這類模型自帶上下文緩存機制&#xff0c;但本文主要針對構建Agent場景下&#xff0c;需要多次調用Anthropic Claude時…