1. 程式人生 > >程序間通訊-跨程序函式呼叫

程序間通訊-跨程序函式呼叫

最近有個專案需要用到程序間通訊,所以設計了一個基於管道的程序間函式呼叫庫,後來因為其他原因沒被採用。但是覺得就這樣扔掉太可惜了,索性把它放出來,說不定能有用。

設計規則如下:

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; // 反序列化類,同序列化類相同