【C++项目】从零实现RPC框架「三」:项⽬抽象层实现

news2025/4/2 22:43:59

🌈 个人主页: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); // 时间戳,获取可读性较强的时间信息S

        char buffer[1024];
        // bug
        snprintf(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.txt
            std::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;            // 进程pid
            std::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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2325812.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

相机镜头景深

文章目录 定义影响因素实际应用特殊情况 参考&#xff1a;B站优致谱视觉 定义 景深是指在摄影机镜头或其他成像器前沿着能够取得清晰图像的成像器轴线所测定的物体距离范围。简单来说&#xff0c;就是在一张照片中&#xff0c;从前景到背景&#xff0c;能够保持清晰锐利的区域…

Linux基础入门:从零开始掌握Linux命令行操作

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f388;有没有觉得电影里的黑客&#x1f412;酷毙了&#xff1f;他们只用键盘⌨就能搞定一切。今天&#xff0c;毛毛张要带你们体验这种快感&#x1f600;&…

C++第13届蓝桥杯省b组习题笔记

1.九进制转十进制 九进制正整数 (2022)9转换成十进制等于多少&#xff1f; 第一位乘9的0次方&#xff0c;第二位乘9的1次方&#xff0c;第三位乘9的二次方以此类推 #include <iostream> using namespace std;int main() {// 请在此输入您的代码int t2022;int res0;int c…

python-leetcode 61.N皇后

题目&#xff1a; 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解…

产教融合|暴雨技术专家执裁江苏省职业院校技能大赛

3月28-30日&#xff0c;由江苏省教育厅、省发改委、省工信厅等15家单位主办的2025年江苏省职业院校技能大赛网络系统管理赛项如期举办。此次赛事吸引了全省52支参赛队伍、156名选手踊跃参与&#xff0c;参赛人数再创新高。 暴雨信息技术专家李明宇作为此赛项的往届省赛冠军&am…

BUUCTF-web刷题篇(6)

15.PHP 知识点&#xff1a; ①__wakeup()//将在反序列化之后立即调用&#xff08;当反序列化时变量个数与实际不符是会绕过&#xff09;我们可以通过一个cve来绕过:CVE-2016-7124。将Object中表示数量的字段改成比实际字段大的值即可绕过wakeup函数。条件&#xff1a;PHP5<…

周总结aa

上周学习了Java中有关字符串的内容&#xff0c;与其有关的类和方法 学习了static表示静态的相关方法和类的使用。 学习了继承(extends) 多态&#xff08;有继承关系&#xff0c;有父类引用指向子类对象&#xff09; 有关包的知识&#xff0c;final关键字的使用&#xff0c;及有…

31天Python入门——第17天:初识面向对象

你好&#xff0c;我是安然无虞。 文章目录 面向对象编程1. 什么是面向对象2. 类(class)3. 类的实例关于self 4. 对象的初始化5. __str__6. 类之间的关系继承关系组合关系 7. 补充练习 面向对象编程 1. 什么是面向对象 面向对象编程是一种编程思想,它将现实世界的概念和关系映…

计算机视觉准备八股中

一边记录一边看&#xff0c;这段实习跑路之前运行完3DGAN&#xff0c;弄完润了&#xff0c;现在开始记忆八股 1.CLIP模型的主要创新点&#xff1a; 图像和文本两种不同模态数据之间的深度融合、对比学习、自监督学习 2.等效步长是每一步操作步长的乘积 3.卷积层计算输入输出…

【C语言】文件操作(2)

一、文件的随机读写 在前面我们学习了文件的顺序读写的函数&#xff0c;那么当我们要读取某个指定位置的内容的时候&#xff0c;是否只能顺序的读取到这个内容&#xff1f;还有在对文件进行输入的时候&#xff0c;需要对指定的位置进行写入&#xff0c;那么此时应该怎么办呢&a…

CCCC天梯赛L1-094 剪切粘贴

题目链接&#xff1a; 字符串函数&#xff1a; 1、截取字符串&#xff1a; //起始位置为3,结束位置为5string s "aabcdefg";//下标从0开始 [从开始位置,结束位置]string sub s.substr(3,3);//输出cde, 有返回值string//并且原字符串不改变&#xff0c; s"aab…

某地81栋危房自动化监测试点项目

1. 项目简介 房屋进入老龄化阶段后&#xff0c;结构安全风险越来越大。近10年来&#xff0c;每年都会产生房屋倒塌人员伤亡的重大安全事故。调研分析显示&#xff0c;老旧房屋结构安全风险管理的有效路径为&#xff0c;通过“人防技防”的组合模式&#xff0c;对房屋安全风险进…

远程装个Jupyter-AI协作笔记本,Jupyter容器镜像版本怎么选?安装部署教程

通过Docker下载Jupyter镜像部署&#xff0c;输入jupyter会发现 有几个版本&#xff0c;不知道怎么选&#xff1f;这几个版本有什么差别&#xff1f; 常见版本有&#xff1a; jupyter/base-notebookjupyter/minimal-notebookjupyter/scipy-notebookjupyter/datascience-notebo…

山东大学软件学院项目创新实训开发日志(4)之中医知识问答数据存储、功能结构、用户界面初步设计

目录 数据库设计&#xff1a; 功能设计&#xff1a; 用户界面: 数据库设计&#xff1a; --对话表 (1个对话包含多条消息) CREATE TABLE conversations ( conv_id VARCHAR(36) PRIMARY KEY, -- 对话ID user_id VARCHAR(36) NOT NULL, -- 所属用户 title VARCHAR(100), -- 对话…

20.思科交换机二层链路聚合的详细配置命令解析

思科交换机二层链路聚合的详细配置命令解析 一、PAgP协议的配置SW1的配置SW2的配置二、LACP标准协议三、配置聚合组的带宽和速率四、确保所有接口的双工模式和速率一致五、故障排除和监控在Cisco设备上配置链路聚合(也称为端口通道或EtherChannel)可以增强网络连接的带宽和可…

【多线程】单例模式和阻塞队列

目录 一.单例模式 1. 饿汉模式 2. 懒汉模式 二.阻塞队列 1. 阻塞队列的概念 2. BlockingQueue接口 3.生产者-消费者模型 4.模拟生产者-消费者模型 一.单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是一种常用的软件设计模式&#xff0c;其核心思想是确保…

Qt5.14.2+Cmake使用mingw64位编译opencv4.5成功图文教程

​ 一、下载安装相关编译环境软件 1.1 Python3.8&#xff1a;安装路径:C:\Users\Administrator\AppData\Local\Programs\Python\Python38-32 安装包&#xff1a;python3.8.exe 1.2 QT5.14.2&#xff1a;安装路径:C:\Qt\Qt5.14.2 1.3 opencv4.5&#xff1a;解压路径D:\o…

Mamba4D阅读

CVPR 2025 创新 基于transformer的4D主干由于其二次复杂度而通常存在较大的计算成本&#xff0c;特别是对于长视频序列。 开发了帧内空间Mamba模块&#xff0c;建立时空相关性。 GPU占用和速度很有优势。 代码还没发。 Pipeline 输入点云序列&#xff0c;根据超参数构建点管…

手工排查后门木马的常用姿势

声明&#xff01;本文章所有的工具分享仅仅只是供大家学习交流为主&#xff0c;切勿用于非法用途&#xff0c;如有任何触犯法律的行为&#xff0c;均与本人及团队无关&#xff01;&#xff01;&#xff01; 1. 检查异常文件 &#xff08;1&#xff09;查找最近修改的文件 # 查…

算法导论(动态规划)——简单多状态

算法思路&#xff08;17.16&#xff09; 状态表示&#xff1a; 在处理线性动态规划问题时&#xff0c;我们可以通过“经验 题目要求”来定义状态表示。通常有两种选择&#xff1a; 以某个位置为结尾的情况&#xff1b;以某个位置为起点的情况。 本题中&#xff0c;我们选择更常…