[实现Rpc] 通信类抽象层 | function | using | 解耦合设计思想

目录

通信抽象类的实现

1.BaseMessage

2.Basebuffer

[3.BaseProtocol & BaseConnection](#3.BaseProtocol & BaseConnection)

4.BaseServer

5.BaseClient


前文:[实现Rpc] 客户端划分 | 框架设计 | common类的实现

  • 通过设计 枚举和宏 提高了项目的可读性

通信抽象类的实现

abs tract.hpp

(1)需要实现的功能:

  • BaseMessage:基础消息类,包含消息的基本操作如序列化、反序列化等。
  • BaseBuffer:缓冲区管理,提供对数据的读写操作。
  • BaseProtocol:协议处理,负责消息的编码和解码。
  • BaseConnection:连接管理,包括发送消息、关闭连接等功能。
  • BaseServer:服务器基类,提供设置回调函数、启动服务器等功能。
  • BaseClient:客户端基类,提供连接服务器、发送消息等功能。

以上实现的各个类都是基类,具体实现的功能由其派生类来实现。

(2)具体实现:

  • 列举出 虚函数名

1.BaseMessage

复制代码
#pragma once
#include <memory>
#include <functional>
#include "fields.hpp"

class BaseMessage
{
public:
    using ptr = std::shared_ptr<BaseMessage>;

    virtual ~BaseMessage() {}
    virtual void SetId(const std:: string &rid) { _rid = rid; }
    virtual std::string GetId() { return _rid; }
    virtual void SetMType(MType type) { _type = type; }
    virtual MType GetMType() { return _type; }
    virtual std::string serialize() = 0;
    virtual bool deserialize(const std::string &msg) = 0;
    virtual bool check() = 0;

private:
    MType _type;
    std::string _rid;
};
  • 不用 new,通过智能指针来管理

参考 前文 文档学习批注:

示例场景

复制代码
class Base {
public:
virtual ~Base() {}
};

class Derived : public Base {
// 如果Base没有虚析构函数,这里可能会导致内存泄漏
};

如果基类析构函数不是虚函数 ,则只会调用BaseMessage的析构函数,导致派生类资源泄漏。

总结

  • using**:简化代码,为** **std::shared_ptr<BaseMessage>**定义别名
  • virtual:确保 继承/多态时 对象的正确析构,是基类设计的核心准则之一。

2.Basebuffer

复制代码
class BaseBuffer {
        public:
            using ptr = std::shared_ptr<BaseBuffer>;
            virtual size_t readableSize() = 0;//可读取 数据大小

            virtual int32_t peekInt32() = 0;//peek 窥视
            virtual void retrieveInt32() = 0;//re tri eve 移除
            virtual int32_t readInt32() = 0;//peek+retrieve 窥视+移除

            virtual std::string retrieveAsString(size_t len) = 0;//读取 指定长度
    };

为什么叫 int32**?**

  • int32_t 是 C++ 中的一个固定宽度整数类型,保证是 32bit 位长。使用int32命名(如peekInt32, retrieveInt32, readInt32)是为了明确表明这些函数处理的是32位整数数据。
  • 32位整数数据是四字节(4 bytes)。8 比特==1 字节

3.BaseProtocol & BaseConnection

复制代码
 class BaseProtocol {//协议
        public:
            using ptr = std::shared_ptr<BaseProtocol>;
            virtual bool canProcessed(const BaseBuffer::ptr &buf) = 0;
//检查 缓冲区 数据是否足够
            virtual bool onMessage(const BaseBuffer::ptr &buf, BaseMessage::ptr &msg) = 0;
//从 缓冲区中 解析出一条数据           
            virtual std::string serialize(const BaseMessage::ptr &msg) = 0;
//序列化
    };

    class BaseConnection {
        public:
            using ptr = std::shared_ptr<BaseConnection>;
            virtual void send(const BaseMessage::ptr &msg) = 0;
//通过连接 发送
            virtual void shutdown() = 0;
//关闭连接
            virtual bool connected() = 0;
//建立连接
    };

1.pro to col 协议


4.BaseServer

复制代码
//类型别名
    using ConnectionCallback = std::function<void(const BaseConnection::ptr&)>;
    using CloseCallback = std::function<void(const BaseConnection::ptr&)>;
    using MessageCallback = std::function<void(const BaseConnection::ptr&, BaseMessage::ptr&)>;

class BaseServer {
        public:
            using ptr = std::shared_ptr<BaseServer>;
            virtual void setConnectionCallback(const ConnectionCallback& cb) {
                _cb_connection = cb;
                //!!!!!!!!实现和BaseConnection部分的解耦合
            }
//新建立连接时的 回调函数
            virtual void setCloseCallback(const CloseCallback& cb) {
                _cb_close = cb;
            }
            virtual void setMessageCallback(const MessageCallback& cb) {
                _cb_message = cb;
            }
//启动服务器
            virtual void start() = 0;
        protected:
            ConnectionCallback _cb_connection;
            CloseCallback _cb_close;
            MessageCallback _cb_message;
    };

⭕前文回顾

  1. function

前文:[C++11#47] (四) function包装器 | bind 函数包装器 | 结合使用

std::function的主要好处在于它能够提供一种 统一的方式来处理不同类型的可调用对象,并且有助于减少由于模板实例化造成的代码膨胀问题。

不过,这也伴随着一定的性能代价,因此在选择是否使用std::function时需要权衡灵活性与性能需求。

  1. why 类似于 _cb_close = cb 设计;

实现了 BaseConnectin 和 BaseServer 函数部分的 解耦合传输

  1. 状态保存 :通过将传入的回调函数(如cb)赋值给类成员变量(如_cb_connection),可以在未来的某个时刻根据需要调用这些回调函数。这意味着当特定事件发生时(例如新连接建立、连接关闭或消息到达),可以执行之前设置好的回调逻辑。
  2. 动态配置:这种设计允许你在运行时动态地改变对象的行为,而不需要修改对象本身的代码。例如,不同的客户端或服务器实例可以根据其具体需求设置不同的回调处理逻辑
  3. 简化接口设计 :通过提供setter方法(如setConnectionCallback),用户可以方便地为对象配置回调逻辑,而不必关心内部如何管理和触发这些回调。

5.BaseClient

复制代码
class BaseClient {
        public:
            using ptr = std::shared_ptr<BaseClient>;
            virtual void setConnectionCallback(const ConnectionCallback& cb) {
                _cb_connection = cb;
            }
            virtual void setCloseCallback(const CloseCallback& cb) {
                _cb_close = cb;
            }
            virtual void setMessageCallback(const MessageCallback& cb) {
                _cb_message = cb;
            }//消息到来



            virtual void connect() = 0;
            virtual void shutdown() = 0;
            virtual bool send(const BaseMessage::ptr&) = 0;
            virtual BaseConnection::ptr connection() = 0;
            virtual bool connected() = 0;
        protected:
            ConnectionCallback _cb_connection;
            CloseCallback _cb_close;
            MessageCallback _cb_message;
    };

BaseConnectionBaseClient 都定义了 send 方法。尽管 BaseConnection 已经有了一个虚函数 send,为什么还需要在 BaseClient 中定义一个 send 方法?

这个问题的答案涉及到 设计模式、职责分离以及接口的一致性和灵活性。

设计考虑

  • 职责分离BaseConnection 负责处理底层的连接细节,比如发送和接收消息 (send, shutdown, connected)。

  • BaseClient 可能需要提供更高层次的功能,例如管理多个连接、处理重连逻辑等。因此,在 BaseClient 中定义 send 方法可以允许客户端实现特定的发送逻辑,而不必直接操作 BaseConnection 的具体实现。

  • 抽象层次 :虽然 BaseConnection 提供了基本的消息发送功能,但是 BaseClient 可能需要对发送的数据进行预处理或后处理(如日志记录、数据加密等)。

  • 通过在 BaseClient 中定义自己的 send 方法,可以实现这些额外的功能,同时保持与 BaseConnection 的接口一致性。

  • 接口统一 :为 BaseClient 定义 send 方法可以使得客户端使用更加直观和统一。用户不需要关心底层的具体连接是如何实现的,只需要调用 BaseClient 提供的方法即可完成所需的操作。这符合面向对象设计中的 "面向接口编程,而不是面向实现编程" 的原则。

  • 扩展性 :如果将来需要改变消息发送的方式(比如增加异步发送的支持),只需修改 BaseClient 中的 send 实现,而无需改动 BaseConnection


继承 vs 重新定义

虽然 BaseClient 可以通过继承直接使用 BaseConnectionsend 方法,但这样做会限制其灵活性和控制力。通过在 BaseClient 中重新定义 send 方法,可以更灵活地控制发送行为,包括但不限于:

  • 在发送前执行某些检查。
  • 对消息内容进行转换或编码。
  • 处理发送失败的情况,并尝试重新发送。

🎢flag: 后续会将 设计模式 部分进行专栏整理,敬请期待~


in va lid 无效的

相关推荐
self-discipline6341 小时前
【计网速通】计算机网络核心知识点与高频考点——数据链路层(二)
网络·网络协议·计算机网络
车载小杜1 小时前
基于指针的线程池
开发语言·c++
CryptoPP1 小时前
深入实践:基于WebSocket的全球化金融数据实时对接方案。 马来西亚、印度、美国金融数据API
websocket·网络协议·金融
网络抓包与爬虫2 小时前
Wireshark——抓包分析
websocket·网络协议·tcp/ip·http·网络安全·https·udp
暴走的YH3 小时前
【网络协议】三次握手与四次挥手
网络·网络协议
云 无 心 以 出 岫3 小时前
贪心算法QwQ
数据结构·c++·算法·贪心算法
仙女很美哦3 小时前
Flutter视频播放、Flutter VideoPlayer 视频播放组件精要
websocket·网络协议·tcp/ip·http·网络安全·https·udp
换一颗红豆3 小时前
【C++ 多态】—— 礼器九鼎,釉下乾坤,多态中的 “风水寻龙诀“
c++
随便昵称4 小时前
蓝桥杯专项复习——前缀和和差分
c++·算法·前缀和·蓝桥杯
commonbelive4 小时前
团体程序设计天梯赛——L1-100 四项全能
c++