RPC分布式通信(3)--RPC基础框架接口

作者:陌路20日期:2026/1/22

一、MprpcApplication 核心职责

MprpcApplication是 RPC 框架的 “管家”,核心作用:

  1. 单例模式:全局唯一实例,避免重复初始化;
  2. 配置加载:解析 RPC 框架的配置文件(如服务器 IP、端口、日志路径、注册中心地址等);
  3. 框架初始化:启动时初始化日志、网络、注册中心等核心组件;
  4. 全局参数访问:提供接口获取配置参数(如获取服务器端口、注册中心地址);
  5. 框架销毁:程序退出时释放资源。

二、MprpcApplication 核心接口设计

以下是工业级 RPC 框架中MprpcApplication的标准接口设计(按功能分类):

接口类型接口名功能描述
单例获取GetInstance()获取全局唯一的MprpcApplication实例(懒汉 / 饿汉单例)
初始化Init(int argc, char** argv)解析命令行参数 + 加载配置文件,初始化框架(核心入口)
配置获取GetConfig(const std::string& key)根据 key 获取配置值(如 "rpcserver_ip")
便捷配置获取GetRpcServerIp()快捷获取 RPC 服务器 IP(封装GetConfig)
便捷配置获取GetRpcServerPort()快捷获取 RPC 服务器端口
便捷配置获取GetZkServerIp()快捷获取 Zookeeper 注册中心 IP
框架销毁Destroy()释放框架资源(日志、网络连接、注册中心句柄等)

三、MprpcApplication 完整实现代码

以下是可直接编译运行的MprpcApplication实现,包含单例、配置加载、参数访问等核心功能:

1. 头文件(mprpcapplication.h)
1#ifndef MPRPCAPPLICATION_H
2#define MPRPCAPPLICATION_H
3
4#include <iostream>
5#include <string>
6#include <unordered_map>
7#include <mutex>
8
9// RPC框架核心应用类(单例模式)
10class MprpcApplication {
11public:
12    // 1. 单例获取:懒汉模式(线程安全)
13    static MprpcApplication& GetInstance();
14
15    // 2. 框架初始化:解析命令行参数 + 加载配置文件
16    // 命令行参数格式:./rpcserver -i config.conf
17    void Init(int argc, char** argv);
18
19    // 3. 通用配置获取接口
20    std::string GetConfig(const std::string& key);
21
22    // 4. 便捷配置获取接口(封装GetConfig,避免重复解析字符串)
23    std::string GetRpcServerIp();   // 获取RPC服务器IP
24    uint16_t GetRpcServerPort();    // 获取RPC服务器端口
25    std::string GetZkServerIp();    // 获取Zookeeper注册中心IP
26    uint16_t GetZkServerPort();     // 获取Zookeeper注册中心端口
27
28    // 5. 框架销毁:释放全局资源
29    void Destroy();
30
31    // 禁止拷贝和移动(单例模式必须)
32    MprpcApplication(const MprpcApplication&) = delete;
33    MprpcApplication& operator=(const MprpcApplication&) = delete;
34    MprpcApplication(MprpcApplication&&) = delete;
35    MprpcApplication& operator=(MprpcApplication&&) = delete;
36
37private:
38    // 私有构造/析构:单例模式
39    MprpcApplication() = default;
40    ~MprpcApplication() = default;
41
42    // 解析配置文件(内部辅助函数)
43    void LoadConfigFile(const std::string& config_file);
44
45    // 全局配置存储(key-value)
46    std::unordered_map<std::string, std::string> m_config_map;
47
48    // 单例锁(保证线程安全)
49    static std::mutex m_mutex;
50    static MprpcApplication* m_instance;
51};
52
53#endif // MPRPCAPPLICATION_H
54
2. 实现文件(mprpcapplication.cpp)
1#include "mprpcapplication.h"
2#include <unistd.h>
3#include <string.h>
4#include <sstream>
5
6// 静态成员初始化
7MprpcApplication* MprpcApplication::m_instance = nullptr;
8std::mutex MprpcApplication::m_mutex;
9
10// 1. 获取单例实例(线程安全的懒汉模式)
11MprpcApplication& MprpcApplication::GetInstance() {
12    if (m_instance == nullptr) {
13        std::lock_guard<std::mutex> lock(m_mutex);
14        if (m_instance == nullptr) {
15            m_instance = new MprpcApplication();
16        }
17    }
18    return *m_instance;
19}
20
21// 2. 框架初始化核心逻辑
22void MprpcApplication::Init(int argc, char** argv) {
23    if (argc < 2) {
24        std::cerr << "usage: " << argv[0] << " -i <config_file>" << std::endl;
25        exit(EXIT_FAILURE);
26    }
27
28    // 解析命令行参数(-i 指定配置文件)
29    int opt = 0;
30    std::string config_file;
31    while ((opt = getopt(argc, argv, "i:")) != -1) {
32        switch (opt) {
33            case 'i':
34                config_file = optarg;
35                break;
36            case '?':
37                std::cerr << "invalid option: " << static_cast<char>(optopt) << std::endl;
38                exit(EXIT_FAILURE);
39            case ':':
40                std::cerr << "option " << static_cast<char>(optopt) << " requires an argument" << std::endl;
41                exit(EXIT_FAILURE);
42            default:
43                break;
44        }
45    }
46
47    // 加载配置文件
48    LoadConfigFile(config_file);
49
50    // 初始化日志/网络等组件(可扩展)
51    std::cout << "MprpcApplication init success!" << std::endl;
52    std::cout << "rpcserver_ip: " << GetRpcServerIp() << std::endl;
53    std::cout << "rpcserver_port: " << GetRpcServerPort() << std::endl;
54    std::cout << "zookeeper_ip: " << GetZkServerIp() << std::endl;
55    std::cout << "zookeeper_port: " << GetZkServerPort() << std::endl;
56}
57
58// 解析配置文件(格式:key=value,忽略注释行#)
59void MprpcApplication::LoadConfigFile(const std::string& config_file) {
60    FILE* fp = fopen(config_file.c_str(), "r");
61    if (fp == nullptr) {
62        std::cerr << "config file " << config_file << " not exist!" << std::endl;
63        exit(EXIT_FAILURE);
64    }
65
66    // 逐行解析配置
67    char buf[512] = {0};
68    while (fgets(buf, sizeof(buf), fp) != nullptr) {
69        // 去掉换行符/空格
70        std::string line(buf);
71        Trim(line);
72
73        // 跳过空行/注释行
74        if (line.empty() || line[0] == '#') {
75            continue;
76        }
77
78        // 解析key=value
79        size_t pos = line.find('=');
80        if (pos == std::string::npos) {
81            // 配置格式错误
82            continue;
83        }
84
85        std::string key = line.substr(0, pos);
86        std::string value = line.substr(pos + 1);
87        Trim(key);
88        Trim(value);
89        m_config_map[key] = value;
90    }
91
92    fclose(fp);
93}
94
95// 辅助函数:去除字符串首尾空格(内部使用)
96void Trim(std::string& s) {
97    size_t start = s.find_first_not_of(" \t\r\n");
98    if (start == std::string::npos) {
99        s = "";
100        return;
101    }
102    size_t end = s.find_last_not_of(" \t\r\n");
103    s = s.substr(start, end - start + 1);
104}
105
106// 3. 通用配置获取
107std::string MprpcApplication::GetConfig(const std::string& key) {
108    auto it = m_config_map.find(key);
109    if (it == m_config_map.end()) {
110        return "";
111    }
112    return it->second;
113}
114
115// 4. 便捷配置获取(封装类型转换)
116std::string MprpcApplication::GetRpcServerIp() {
117    return GetConfig("rpcserver_ip");
118}
119
120uint16_t MprpcApplication::GetRpcServerPort() {
121    std::string port_str = GetConfig("rpcserver_port");
122    return std::stoi(port_str);
123}
124
125std::string MprpcApplication::GetZkServerIp() {
126    return GetConfig("zookeeper_ip");
127}
128
129uint16_t MprpcApplication::GetZkServerPort() {
130    std::string port_str = GetConfig("zookeeper_port");
131    return std::stoi(port_str);
132}
133
134// 5. 框架销毁(释放资源)
135void MprpcApplication::Destroy() {
136    // 释放日志资源、网络连接、zk客户端句柄等(可扩展)
137    std::cout << "MprpcApplication destroy success!" << std::endl;
138    if (m_instance != nullptr) {
139        delete m_instance;
140        m_instance = nullptr;
141    }
142}
143
3. 配置文件示例(config.conf)
1# RPC框架配置文件
2# 服务器配置
3rpcserver_ip=127.0.0.1
4rpcserver_port=8080
5
6# Zookeeper注册中心配置
7zookeeper_ip=127.0.0.1
8zookeeper_port=2181
9
10# 日志配置(可扩展)
11log_path=./log
12log_level=info
13
4. 测试使用示例(main.cpp)
1#include "mprpcapplication.h"
2
3int main(int argc, char** argv) {
4    // 1. 初始化RPC框架(核心步骤)
5    MprpcApplication::GetInstance().Init(argc, argv);
6
7    // 2. 获取配置参数
8    std::string rpc_ip = MprpcApplication::GetInstance().GetRpcServerIp();
9    uint16_t rpc_port = MprpcApplication::GetInstance().GetRpcServerPort();
10    std::cout << "=== 业务层获取配置 ===" << std::endl;
11    std::cout << "RPC Server IP: " << rpc_ip << std::endl;
12    std::cout << "RPC Server Port: " << rpc_port << std::endl;
13
14    // 3. 运行RPC服务器/客户端逻辑(可扩展)
15    // ...
16
17    // 4. 销毁框架(程序退出前)
18    MprpcApplication::GetInstance().Destroy();
19
20    return 0;
21}
22
四、核心设计要点解析
  1. 单例模式
    • 采用懒汉模式 + 双检锁,保证线程安全且延迟初始化;
    • 禁用拷贝 / 移动构造,避免多实例创建。
  2. 配置解析
    • 支持命令行参数-i指定配置文件,符合 Linux 程序习惯;
    • 解析key=value格式,忽略注释行和空行,兼容常见配置文件格式。
  3. 扩展性设计
    • 通用GetConfig接口兼容新增配置项;
    • 便捷接口(如GetRpcServerPort)封装类型转换,降低业务层使用成本;
    • Destroy函数预留资源释放接口,可扩展日志、网络、注册中心等资源释放。
  4. 错误处理
    • 初始化失败时直接退出并打印错误信息,避免框架带病运行;
    • 配置文件不存在 / 格式错误时友好提示。

五、扩展方向(工业级优化)

  1. 配置热更新:添加ReloadConfig接口,支持不重启程序更新配置;
  2. 配置校验:初始化时校验必填配置(如rpcserver_port必须是合法端口);
  3. 日志集成:整合你之前的日志系统,将框架日志写入指定路径;
  4. 注册中心初始化:在Init中初始化 Zookeeper 客户端,封装到MprpcApplication
  5. 饿汉模式:若框架启动时必须初始化,可改为饿汉单例(提前创建实例)。

总结

  1. MprpcApplication是 RPC 框架的入口类,核心是单例管理 + 配置加载 + 全局参数访问
  2. 核心接口Init负责框架初始化,GetConfig/ 便捷接口负责参数获取,Destroy负责资源释放;
  3. 设计要点:线程安全的单例、灵活的配置解析、低耦合的扩展接口。

关键点回顾

  1. 单例模式:懒汉 + 双检锁,保证全局唯一且线程安全;
  2. 初始化流程:解析命令行参数 → 加载配置文件 → 初始化核心组件;
  3. 配置访问:通用接口兼容扩展,便捷接口降低使用成本。

RPC分布式通信(3)--RPC基础框架接口》 是转载文章,点击查看原文


相关推荐


【计算机网络 | 第三篇】MAC地址与IP地址
YYYing.2026/1/14

目录 MAC地址 一、MAC地址的格式特征 二、MAC地址的获取 三、什么是ARP? 四、ARP缓存 五、RARP IP地址 一、为什么要有IP地址? 二、既然IP地址存在,那它的意义是什么? 三、那又如何表示呢? 1、IP地址的定义 2、IPv4地址的表示方法 2.1、IPv4地址的分类编址方法 2.2、IPv4地址的划分子网编址方法 2.2.1、为什么要划分子网? 2.2.2、怎么划分子网? 2.2.3、总结 2.3、IPv4地址的无分类编址方法 3、构


Rust 的 `PhantomData`:零成本把“语义信息”交给编译器
Pomelo_刘金2026/1/5

在写底层 Rust(尤其是 unsafe / 裸指针 / FFI)时,你会遇到一种常见矛盾: 运行时:你手里可能只有一个 *const T / *mut T / *mut c_void(比如外部库返回的句柄),结构体里并没有真正存放某个引用或某个类型的值。 编译期:你又希望编译器知道“我这个类型和某个生命周期/类型绑定”,从而帮你做借用检查、推导 Send/Sync、避免错误混用等。 std::marker::PhantomData<T> 就是为了解决这个问题而存在的工具。官方文档的核心定义


前端开发者使用 AI 的能力层级——从表面使用到工程化能力的真正分水岭
月亮有石头2025/12/28

很多前端开发者已经在“使用 AI”: 会问问题、会让 AI 写代码、甚至在 IDE 里和 AI 对话。 但如果这些使用方式 无法稳定地产出可运行、可验证、可回归的工程结果, 那么严格来说——其实还没有真正入门。 这篇文章想系统回答一个问题: 前端开发者“使用 AI”的能力,是有明确层级和分水岭的。 不是工具多不多,也不是模型新不新, 而是:你用 AI 的方式,决定了它在你工程体系里的角色。 把 AI 放进工程链路,用工程约束对抗幻觉,用验证与反馈逼近真实。 AI 工程化的本质,并不是让模型


Node.js 编程实战:文件读写操作
程序员爱钓鱼2025/12/19

在后端开发中,文件读写是非常常见的需求,例如日志记录、配置文件管理、上传文件处理以及数据导入导出等。Node.js 提供了内置的 fs(File System)模块,使得我们可以高效地与文件系统进行交互。理解并掌握 Node.js 的文件读写方式,是每一个 Node.js 开发者的必备基础。 一、fs 模块简介 fs 模块是 Node.js 的核心模块之一,无需额外安装即可直接使用。它提供了同步和异步两套 API,用于完成文件的创建、读取、写入、删除以及目录操作等功能。 在实际开发中,Nod


大模型 MoE,你明白了么?
吴佳浩2025/12/11

大模型 MoE,你明白了么? 最近被T4卡搞得有点抽风就多些一点关于大模型的讲解的。由浅至深的讲个透,愿天下用老旧显卡的人儿都可以远离傻*问题。 作者:吴佳浩 最后更新:2025-12-11 适用人群:大模型上下游相关从业者 ——以 Qwen2/Qwen3 为例,从入门到回家 1. 什么是 MoE(Mixture of Experts) 核心概念 MoE = 混合专家模型,它让模型由多个"专家网络"组成,每次推理只激活少量专家,从而实现: ✅ 保留大模型能力 - 总参数量大,能力强 ✅


使用 useSearchParams 同步 URL 和查询参数
mCell2025/12/2

同步至个人站点:useSearchParams 使用 useSearchParams 同步 URL 和查询参数 在开发 React 应用时,我们经常遇到一种场景:用户在搜索框输入关键词,筛选出一个列表,然后希望把这个结果分享给同事。 如果我们将筛选条件仅仅保存在组件的 useState 中,一旦刷新页面或复制链接,这些状态就会丢失,用户看到的只能是初始页面。 为了解决这个问题,我们需要将状态“提升”到 URL 的查询参数(Query Params)中。在 React Router v6 中,u

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客