Java RMI 依賴反射機制動態發現與調用遠程方法。標準 C++ 無反射,Boost.RCF 雖提供類似功能,但依賴 Boost.Serialization、編譯繁瑣且有諸多限制。本文展示一套純 C++ 實作的輕量級 RMI 框架,利用宏替換、模板、虛擬函數、函數物件等技術,模擬遠程方法調用,無需外部依賴,跨平台可移植。
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;
};
// 宣告伺服端模板類別
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
// 宣告客戶端模板類別(介面需與伺服端一致)
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++ | 無第三方依賴,跨平台移植容易 |
| 原始碼發布 | 直接包含原始檔,無需動態庫 |
本框架展示 C++ 強大的代碼復用技術(宏、模板、虛擬函數、函數物件)如何彌補語言層面缺乏反射的不足。雖非生產級 RMI 替代品,但作為教學範例與輕量級 RPC 起點極具價值。完整原始碼可聯繫作者獲取。