刚刚搬来这个温暖的C++大家庭,就已经发现有高手在开发C++的RMI了。
我一直都在留意
www.codeproject.com的一个项目:
http://www.codeproject.com/threads/RMI_For_Cpp.asp作者并在不断的完善中,但也基本上能用了。
calvin前几天又提醒过我一次,一个久违的project:
http://acdk.sourceforge.net/ 里面也实现了类似的RMI技术。(当然是模仿Java的RMI,而且模仿得很像)。
个人比较讨厌类似于ICE那种,需要通过一个外部工具编译IDL的做法,不利于集成开发:老要在IDE上做些手脚,以实现自动预编译;要找相应的语法解释器解释IDL,否则编辑困难;由于不是源代码的一部分,代码管理上经常会有些混乱……所以反而比较喜欢类似于RMI for c++这种,把接口的描述也作为源代码的一部分。而且由于都是C++语言的一部分,不会有太多的额外工作。
但在本人的实际工作中,RMI却不如想象中这么有效。
首先,就是参数传递。很多情况下,调用一个函数,会传入一些参数。既然是面向对象开发,传入一个对象的情况是不可避免的。例如:
int func(TMyObject & a);
TMyObject可能是一个很庞大,很复杂的类,但func里面可能只需要访问其中80%的成员变量。但是只通过IDL的接口,不可能知道究竟函数里面需要哪些数据,所以一般根据IDL生成的辅助代码,都会是把整个TMyObject对象序列化并传递。当TMyObject相当庞大的时候,这个浪费相当厉害。更好的做法只好把func所需要的参数逐个排列出来作为func的参数。但这样func用起来就变得极为麻烦了。
其次就是数据流的处理问题。经常会出现类似于int func(stream & a, stream & b);的函数调用。对于客户端,缺省的实现容易理解,按顺序把两个stream中的数据序列化就可以了。但是在服务器端,代码就没有这么好写了。由于stream一般都是一个虚类,因此IDL生成的辅助代码就要想办法用一种具体stream子类,把网络数据先收下来,然后再传给实际的func函数。而这个stream的子类也比较头疼,应该选内存还是临时文件呢?还是更智能一点,小数据内存、大数据文件呢?但无论是哪种方法,都要考虑数据的回收和生存期的问题。另外不爽的地方就是数据要接收完毕才能真正执行func,从而数据是多拷贝了一次了。
当然这里所说的问题对于一般应用都无关痛痒,但对于一些性能要求比较高的场合,RMI自动生成的stub就无能为力了。
RMI往往也和反射、成员序列化等技术相关。而且通常还要涉及到通讯版本差异处理、异常处理等等。像ICE还增加了异步处理、对象发现等等。所以要做一个完整的RMI,的确不是容易的事情。