首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

讓 C++ 也支援 RMI:基於宏與模板的遠程方法調用實作

     編輯:關於C++

前言:C++ 缺乏反射,如何實現 RMI?

Java RMI 依賴反射機制動態發現與調用遠程方法。標準 C++ 無反射,Boost.RCF 雖提供類似功能,但依賴 Boost.Serialization、編譯繁瑣且有諸多限制。本文展示一套純 C++ 實作的輕量級 RMI 框架,利用宏替換、模板、虛擬函數、函數物件等技術,模擬遠程方法調用,無需外部依賴,跨平台可移植。

核心架構

  • RMIClientBase: 客戶端通訊基類,管理 TCP 連線、序列化參數、發送請求、接收回應。
  • RMIServerBase: 伺服端通訊基類,監聽埠、多執行緒處理請求、反序列化參數、呼叫本地函數、回傳結果。
  • FunctionObject: 函數物件模板,封裝函數 ID 與參數,客戶端調用時自動生成存根(Stub)並透過基類發送。
  • RemoteFunctionStub: 函數存根結構,攜帶函數 ID、參數列表、返回值資訊。
  • ParaListAnalyser: 參數解析器模板,伺服端將位元組流還原為強型別參數。

使用範例:計算服務

1. 定義服務介面類別

class Calculate {
public:
    int sum(int a, int b) {
        printf("int sum called\n"); return a + b;
    }
    double sum(double a, double b) {
        printf("double sum called\n"); return a + b;
    }
    int GetInput() {
        int a; printf("Enter int: "); scanf("%d", &a); return a;
    }
    Student GetStudent(Teacher tt) {
        Student ts; ts.age = 10; strcpy(ts.name, "StudentJim"); ts.sex = 1;
        printf("GetStudent called, teacher: %s %d\n", tt.name, tt.age);
        return ts;
    }
    int t1, t2;
};

2. 伺服端部署(宏聲明與實例化)

// 宣告伺服端模板類別
MY_RMI_SERVER_CLASS_DECLARE(RMIServer)
MY_RMI_SERVER_FUNCTION_ADD_P2(int, sum, int, int)
MY_RMI_SERVER_FUNCTION_ADD_P2(double, sum, double, double)
MY_RMI_SERVER_FUNCTION_ADD_P0(int, GetInput)
MY_RMI_SERVER_FUNCTION_ADD_P1(Student, GetStudent, Teacher)
MY_RMI_SERVER_CLASS_END()

// 實例化並啟動
RMIServer<Calculate> ServerCalculate;
Calculate calcObj;
ServerCalculate.AddLocalObject(&calcObj);
ServerCalculate.Listen(663); // 監聽埠 663

3. 客戶端調用

// 宣告客戶端模板類別(介面需與伺服端一致)
MY_RMI_CLIENT_CLASS_DECLARE(RMIClient)
MY_RMI_CLIENT_FUNCTION_ADD_P2(int, sum, int, int)
MY_RMI_CLIENT_FUNCTION_ADD_P2(double, sum, double, double)
MY_RMI_CLIENT_FUNCTION_ADD_P0(int, GetInput)
MY_RMI_CLIENT_FUNCTION_ADD_P1(Student, GetStudent, Teacher)
MY_RMI_CLIENT_CLASS_END()

// 連線並調用
RMIClient<Calculate> ClientCalculate;
ClientCalculate.Connect("127.0.0.1", 663);

int n = ClientCalculate.sum(2, 33);
double d = ClientCalculate.sum(2.2, 33.21);
n = ClientCalculate.GetInput();
Teacher t1; Student s1 = ClientCalculate.GetStudent(t1);

關鍵技術解析

宏定義機制

  • MY_RMI_SERVER_CLASS_DECLARE:產生繼承 RMIServerBase 的模板類別,含建構子、AddLocalObject 綁定本地物件、純虛擬 CallLocalFunction 骨架。
  • MY_RMI_SERVER_FUNCTION_ADD_Pn:在 CallLocalFunction 中追加 if (strcmp(funcID, "生成ID") == 0) 分支,解析參數、呼叫本地函數、序列化返回值。
  • JOINSTRINGn:將返回型別、函數名、參數型別拼接為唯一函數 ID(如 "intsumintint")。
  • 客戶端宏同理產生同名成員函數,內部建構 FunctionObject 發送請求。

函數物件與存根

template <typename R, typename P1, typename P2>
class FunctionObject {
public:
    R operator()(const char* funcID, RMIClientBase* pClient, P1 p1, P2 p2) {
        RemoteFunctionStub stub;
        stub.funcID = funcID;
        stub.params = Serialize(p1, p2); // 簡化示意
        pClient->CallRemoteFunction(&stub);
        return Deserialize<R>(stub.result);
    }
};

多執行緒伺服端

  • ListenThread:主執行緒監聽 accept(),每新連線啟動 ProcessRequest 執行緒。
  • ProcessRequest:接收存根、呼叫 CallLocalFunction、回傳結果。執行緒間自動同步互斥。

主要特點與優勢

特性說明
實作簡單無需手寫 switch-case 序列化,宏自動生成
強型別模板參數保證參數/返回型別編譯期檢查
動態擴充新增方法只需在類別與宏中同步聲明
通訊可控AddLocalObject 可動態綁定不同實例(RCF 無此功能)
多執行緒伺服端每請求一執行緒,不阻塞主邏輯
執行緒安全內建互斥同步
標準 C++無第三方依賴,跨平台移植容易
原始碼發布直接包含原始檔,無需動態庫

已知限制與改進方向

  • 安全性: 缺乏鑑權,任何知悉介面者皆可調用。需加入 Token/TLS。
  • 不支援指標/引用參數: 需擴充序列化機制處理物件圖。
  • 無連線日誌統計: 可加入連線計數、請求時間記錄。
  • 錯誤處理簡略: 網路異常(斷線、超時)未完善處理。
  • 序列化效能: 文字/二進制手工序列化,可引入 FlatBuffers/Protocol Buffers/MessagePack。

結語

本框架展示 C++ 強大的代碼復用技術(宏、模板、虛擬函數、函數物件)如何彌補語言層面缺乏反射的不足。雖非生產級 RMI 替代品,但作為教學範例與輕量級 RPC 起點極具價值。完整原始碼可聯繫作者獲取。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved