程序間通訊-跨程序函式呼叫
最近有個專案需要用到程序間通訊,所以設計了一個基於管道的程序間函式呼叫庫,後來因為其他原因沒被採用。但是覺得就這樣扔掉太可惜了,索性把它放出來,說不定能有用。
設計規則如下:
1. 使用Windows管道作為底層通訊方式;只考慮點對點之間的通訊。
2. 在管道之上定義一套規則,用來傳遞函式引數和返回值。
3. 使用模板讓引數和返回值的序列化更加方便也容易擴充套件。
4. 支援回撥,雙發可以互調對方的函式。
5. 採用C++
程式碼位置:
svn地址
svn
checkout http://remote-function.googlecode.com/svn/trunk/
remote-function-read-only
專案首頁http://code.google.com/p/remote-function/
設計思想:
1. 函式呼叫方(程序)和函式執行方(程序)之間先建立好管道連線。
2. 函式執行方註冊可以執行的函式:函式型別名和函式名。函式型別名在執行的時候可以確認各引數的類似和返回值型別。函式名用來區分不同的函式。
例如函式 int add(int a, int b)
他的函式名為"add";函式型別名為typeid(add).name()
3. 函式呼叫方,拿到一個add函式的呼叫代理,使用該代理遠端呼叫代理。
例如 : proxy = get_proxy("add") ;獲取函式名為add的代理
int c = proxy.makecall<int>(3, 5); // 呼叫,需要指定函式值型別。引數型別直接通過模板推導得到。
底層會序列化引數和函式型別、函式名;通過管道傳送給執行方。
4. 函式執行方;接收到傳送過來的資料,根據函式名和函式型別找到對應的函式執行,再將結果序列化之後通過管道傳送返回。
5. 函式呼叫方,反序列化返回值,並從makecall<int>()返回。
使用示例(省略了管道建立過程,詳細參見程式碼):
執行方
class remote_function; // 遠端呼叫類
remote_function rfserver;
rfserver.entry("add", add); // 此處的add型別直接由模板推導得到。
rfserver.start_service(); // 迴圈等待並執行遠端呼叫
呼叫方
remote_function rfclient;
rfclient.start_service();
proxy p = rfclient["add"]; // 獲取一個函式名為add的呼叫代理。函式型別由makecall時自動推匯出
int c = p.makecall<int>(3, 4); // 呼叫函式型別為 int (*fun)(int, int)的函式,執行方必須註冊了int (*fun)(int, int)或者 int (Class::*fun)(int, int)之類的函式。
因為程式碼裡面用到了一些模板的方法,要描述清楚,對我來說難度太大;可能看了半天也不明白,所以,有興趣可以先看看跑下例子(VS2008),再結合程式碼看看吧。^_^
下面是是一些限制和缺陷。
1. 每一方的函式都是按序執行的,所以要注意A呼叫B的f1函式,f1函式呼叫A的f2函式,f2的函式又呼叫A的函式,會發生死鎖。
2. 不支援引用傳遞/指標返回值。以後開是否有空,支援一下這種模式。
3. 目前只支援0個引數,1個引數,2個引數的函式呼叫;多引數的可以自己仿照新增。
4. 返回值不能是void
主要資料結構介紹,具體參見原始碼:
class pipe; // 簡單封裝了window管道。起了兩個執行緒,一個執行緒用來接受資料,一個用來發送資料。
class remote_function; // 呼叫規則實現者。
class function_proxy; // 呼叫代理
class serial; // 序列化類
內建支援
1)基本型別int, char,long...,等型別的序列化
2)有基本型別構成的結構體
3)由基本型別或2)構成的結構體
4)支援std::string
5)不支援指標序列化。
6) 自定義型別可以自己寫序列化。
class unserial; // 反序列化類,同序列化類相同