
?? 個人主頁:Zfox_
?? 系列專欄:C++從入門到精通

目錄
- 一:?? 常?的零碎功能接?類實現
- ?? 簡單?志宏實現
- ?? Json 序列化/反序列化
- ?? UUID ?成
- 二:?? 項?消息類型字段信息定義
- ?? 請求字段宏定義
- ?? 消息類型定義
- ?? 響應碼類型定義
- ?? RPC 請求類型定義
- ?? 主題操作類型定義
- ?? 服務操作類型定義
- 三:?? 通信抽象實現
- 四:?? 消息抽象實現
- 五:?? 通信 - Muduo 封裝實現
- 六:?? Dispatcher 實現
- 七:?? 共勉
一:?? 常?的零碎功能接?類實現
detail.hpp
?? 簡單?志宏實現
????? 意義:快速定位程序運?邏輯出錯的位置。
項?在運?中可能會出現各種問題,出問題不可怕,關鍵的是要能找到問題,并解決問題。
解決問題的?式:
- gdb 調試:逐步調試過于繁瑣,緩慢。主要?于程序崩潰后的定位。
- 系統運??志分析:在任何程序運?有可能邏輯錯誤的位置進?輸出提?,快速定位邏輯問題的位置。
#include <iostream>
#include <cstdio>
#include <string>
#include <fstream>
#include <sstream>
#include <memory>
#include <filesystem> // c++17
#include <random>
#include <time.h>
#include "Mutex.hpp"namespace rpc
{using namespace LockModule;// 獲取一下當前系統的時間std::string CurrentTime(){time_t time_stamp = ::time(nullptr);struct tm curr;localtime_r(&time_stamp, &curr); // 時間戳,獲取可讀性較強的時間信息Schar buffer[1024];// bugsnprintf(buffer, sizeof(buffer), "%4d-%02d-%02d %02d:%02d:%02d",curr.tm_year + 1900,curr.tm_mon + 1,curr.tm_mday,curr.tm_hour,curr.tm_min,curr.tm_sec);return buffer;}// 構成:1. 構建日志字符串 2. 刷新落盤(screen, file)// 1. 日志文件的默認路徑和文件名const std::string defaultlogpath = "./log/";const std::string defaultlogname = "log.txt";// 2. 日志等級enum class LogLevel{DEBUG = 1,INFO,WARNING,ERROR,FATAL};std::string Level2String(LogLevel level){switch (level){case LogLevel::DEBUG:return "DEBUG";case LogLevel::INFO:return "INFO";case LogLevel::WARNING:return "WARNING";case LogLevel::ERROR:return "ERROR";case LogLevel::FATAL:return "FATAL";default:return "None";}}// 3. 刷新策略class LogStrategy{public:virtual ~LogStrategy() = default;virtual void SyncLog(const std::string &message) = 0;};// 3.1 控制臺策略class ConsoleLogStrategy : public LogStrategy{public:ConsoleLogStrategy(){}~ConsoleLogStrategy(){}void SyncLog(const std::string &message){LockGuard lockguard(_lock);std::cout << message << std::endl;}private:Mutex _lock;};// 3.2 文件級(磁盤)策略class FileLogStrategy : public LogStrategy{public:FileLogStrategy(const std::string &logpath = defaultlogpath, const std::string &logname = defaultlogname): _logpath(logpath), _logname(logname){// 確認_logpath是存在的LockGuard lockguard(_lock);if (std::filesystem::exists(_logpath)){return;}try{std::filesystem::create_directories(_logpath);}catch (const std::filesystem::filesystem_error &e){std::cerr << e.what() << '\n';}}~FileLogStrategy(){}void SyncLog(const std::string &message){LockGuard lockguard(_lock);std::string log = _logpath + _logname; // ./log/log.txtstd::ofstream out(log, std::ios::app); // 日志寫入,一定是追加if (!out.is_open()){return;}out << message << '\n';out.close();}private:std::string _logpath;std::string _logname;Mutex _lock;};// 日志類:構建日志字符串,根據策略,進行刷新class Logger{public:Logger(){// 默認采用ConsoleLogStrategy策略_strategy = std::make_shared<ConsoleLogStrategy>();}void EnableConsoleLog(){_strategy = std::make_shared<ConsoleLogStrategy>();}void EnableFileLog(){_strategy = std::make_shared<FileLogStrategy>();}~Logger(){}// 一條完整的信息:[2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] + 日志的可變部分(<< "hello world" << 3.14 << a << b;)class LogMessage{public:LogMessage(LogLevel level, const std::string &filename, int line, Logger &logger): _currtime(CurrentTime()), _level(level), _pid(::getpid()), _filename(filename), _line(line), _logger(logger){std::stringstream ssbuffer;ssbuffer << "[" << _currtime << "] "<< "[" << Level2String(_level) << "] "<< "[" << _pid << "] "<< "[" << _filename << "] "<< "[" << _line << "] - ";_loginfo = ssbuffer.str();}template <typename T>LogMessage &operator<<(const T &info){std::stringstream ss;ss << info;_loginfo += ss.str();return *this;}~LogMessage(){if (_logger._strategy){_logger._strategy->SyncLog(_loginfo);}}private:std::string _currtime; // 當前日志的時間LogLevel _level; // 日志等級pid_t _pid; // 進程pidstd::string _filename; // 源文件名稱??int _line; // 日志所在的行號Logger &_logger; // 負責根據不同的策略進行刷新std::string _loginfo; // 一條完整的日志記錄};// 就是要拷貝LogMessage operator()(LogLevel level, const std::string &filename, int line){return LogMessage(level, filename, line, *this); // 優化成一次構造一次析構了 連續的構造 + 拷貝構造}private:std::shared_ptr<LogStrategy> _strategy; // 日志刷新的策略方案};Logger logger;#define LOG(Level) logger(Level, __FILE__, __LINE__)
#define ENABLE_CONSOLE_LOG() logger.EnableConsoleLog()
#define ENABLE_FILE_LOG() logger.EnableFileLog()
}
Mutex.hpp 是對Linux下pthread庫的封裝
#pragma once
#include <iostream>
#include <pthread.h>namespace LockModule
{class Mutex{public:Mutex(const Mutex&) = delete;const Mutex& operator = (const Mutex&) = delete;Mutex(){int n = ::pthread_mutex_init(&_lock, nullptr);(void)n;}~Mutex(){int n = ::pthread_mutex_destroy(&_lock);(void)n;}void Lock(){int n = ::pthread_mutex_lock(&_lock);(void)n;}pthread_mutex_t *LockPtr(){return &_lock;}void Unlock(){int n = ::pthread_mutex_unlock(&_lock);(void)n;}private:pthread_mutex_t _lock;};class LockGuard{public:LockGuard(Mutex &mtx):_mtx(mtx){_mtx.Lock();}~LockGuard(){_mtx.Unlock();}private:Mutex &_mtx;};
}
?? Json 序列化/反序列化
#include <iostream>
#include <sstream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>namespace rpc
{class JSON{public:// 實現字符串的序列化static bool Serialize(const Json::Value &val, std::string &body){std::stringstream ss;// 先實例化一個工廠類對象static Json::StreamWriterBuilder swb;// 再使用工廠類對象來生產派生類std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());int ret = sw->write(val, &ss);if (ret != 0){LOG(LogLevel::ERROR) << "Json Serialize failed!";return false;}body = ss.str();return true;}// 實現json字符串的反序列化static bool UnSerialize(const std::string &body, Json::Value &val){// 實例化工廠類對象static Json::CharReaderBuilder crb;std::unique_ptr<Json::CharReader> cr(crb.newCharReader());std::string errs;bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &val, &errs);if (ret == false){LOG(LogLevel::ERROR) << "Json UnSerialize failed! " << errs;return false;}return true;}};
}
?? UUID ?成
UUID (UniversallyUniqueIdentifier),也叫通?唯?識別碼,通常由32位16進制數字字符組成。 UUID的標準型式包含32個16進制數字字符,以連字號分為五段,形式為8-4-4-4-12的32個字符,
如:550e8400-e29b-41d4-a716-446655440000。
在這?,uuid?成,我們采??成8個隨機數字,加上8字節序號,共16字節數組?成32位16進制字符的組合形式來確保全局唯?的同時能夠根據序號來分辨數據(隨機數?眼分辨起來真是太難了…)
#include <iostream>
#include <chrono>