- 浏览: 491617 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
hypercube:
markin'
配置D语言编程环境 -
qiezi:
qiezi 写道yangyang_08 写道1 ...
我的编程语言学习经历 -
qiezi:
yangyang_08 写道1、现在如果做并发服务器,楼主选用 ...
我的编程语言学习经历 -
yangyang_08:
1、现在如果做并发服务器,楼主选用什么样的语言架构?2、lua ...
我的编程语言学习经历 -
dearplain:
我也是语言爱好者,不过我一直坚持使用c。
我的编程语言学习经历
一、问题。
这段时间考虑实现一个纯C++的分布式服务包装库,简要描述如下:
有如下类和函数:
{
void test1 (/*in*/ int v1, /*in*/ int* v2);
int test2 (/*in*/ int& v1, /*out*/ int* v2);
};
int test_func (/*in*/ int* v1, /*inout*/ string* v2);
想把它们作为服务发布出去,以SOAP或其它方式。发布为一个TestService,并让它携带多一些信息:
{
void test1 (in<int> v1, in<int> v2);
int test2 (in<int> v1, out<int> v2);
int test_func (in<int> v1, inout<string> v2);
};
C++有许多工具、库来做到这点,但是,都需要生成一堆代码,很是不爽。
其它语言,比如python, java, c#等,都可以通过自省机制,抛开IDL在语言内实现。
C++并非不能做这个,它只是缺少足够的类型信息。比如上面的例子,如果要发布为服务,那么至少应该把它的参数、返回值搞得明确些,否则要么会造成不必要的参数传递,要么会产生错误(把OUT参数取值可不是安全的)。
比如上面出现的int, int&, int*,在作为in参数时,我们是想传递它的值,类型为int。而int*和string*作为out参数时,我们想让它传递指针或引用,当调用返回时,我们给它赋值。
C++语言的类型极为丰富,却没有描述一个参数到底是in还是out。java也没有,但它可以正常序列化一个null值,在C++中,这可能存在一些麻烦。
再考虑一下char*类型,假如它是in参数,那么它是要传递一个字符还是一个字符串?C++语言没有对它进行描述。
所以要实现一个分布式服务包装(或代理)库,必须让发布者提供这些信息。
我们知道,要查询一个远程服务,必须查询相应主机端口,获取服务信息。最简单的服务信息包括:服务列表,每个服务中的方法列表,方法的类型(包括参数和返回值类型,in/out信息等)。
实际上,我们是要为C++增加一些简单的自省能力。上面那个服务发布接口,实际上离这个要求还有很远,再来看一下:
{
void test1 (in<int> v1, in<int> v2);
int test2 (in<int> v1, out<int> v2);
int test_func (in<int> v1, inout<string> v2);
};
可以想见,它是没有一点自省能力的,我们如何向它查询,它的名字?它的方法列表?方法的类型?它如何与Test类的成员函数以及test_func函数关联?
二、方向。
要让上面那个服务具有自省能力,要做的扩充其实并不多。考虑下面的代码:
{
TestService ();
Method <void(in<int>, in<int>)> test1;
Method <int(in<int>, out<int>)> test2;
Method <int(in<int>, inout<string>) test_func;
};
这几个Method可以用自己写的委托类来做。
1、假如我们在TestService的构造函数里给它分配一个“TestService”名字,并且Service类实现了查询名字的接口,那么它就知道它自己的名字了。
2、假如在TestService的构造函数里为各个Method分配名字,并且注册到TestService,那么它就能够查询方法列表。
3、方法的类型?通过模板方式,把各个参数类型收集起来,给个字符串名称就可以了。
使用宏来实现,大概可以写成这样:
METHOD (void(in<int>, in<int>), test1, &Test::test1)
METHOD (int(in<int>, out<int>), test2, &Test::test2)
METHOD (int<in<int>, inout<string>), test_func, test_func)
END_SERVICE ()
通过上面这几个宏,我们能够生成TestService声明。
不过,有几个问题,罗列如下,并一一解决它:
1、如何把函数指针传给它?如何把方法名称传给它?
这个只是C++语言为我们增加了一些麻烦,我们无法在定义成员的地方调用它的构造函数,不过这并不会造成多大障碍。
上面的METHOD宏如果只是生成类的声明,那么函数指针可以省略。我把它加上的原因是,它可以被我用Ctrl+C, Ctrl+V这种世界上最先进的技术原样拷贝下来,并且通过简单修改的方法实现这种世界上最先进的重用。
上面的代码经过修改,结果就成这样:
METHOD (void(in<int>, in<int>), test1, &Test::test1)
METHOD (int(in<int>, out<int>), test2, &Test::test2)
METHOD (int<in<int>, inout<string>), test_func, test_func)
BEGIN_DEFINE (TestService)
METHOD_DEFINE (void(in<int>, in<int>), test1, &Test::test1)
METHOD_DEFINE(int(in<int>, out<int>), test2, &Test::test2)
METHOD_DEFINE(int(in<int>, inout<string>), test_func, test_func)
END_DEFINE ()
END_SERVICE ()
看上去对应得非常整齐,修改起来也比较简单。上面那部分被扩充为如下代码:
{
Method <void(in<int>, in<int>)> test1;
Method <int(in<int>, out<int>)> test2;
Method <int(in<int>, inout<string>) test_func;
TestService ()
: Service ("TestService")
{
test1.setName ("test1");
test1.setMethod (&Test::test1);
this->registerMethod (&test1);
test2.setName ("test2");
test2.setMethod (&Test::test2);
this->registerMethod (&test2);
test_func.setName ("test_func");
test_func.setMethod (test_func);
this->registerMethod (&test3);
}
};
基本上需要的东西都在这里了。
2、客户端的问题。
上面这种映射,直接拿到客户端会有问题,Test类和test_func函数我们并不打算交给客户端,所以使用函数指针会出现链接错误。
实际上客户端不需要这个,我们想办法把它拿掉就行了。客户端实际需要生成的代码如下:
{
Method <void(in<int>, in<int>)> test1;
Method <int(in<int>, out<int>)> test2;
Method <int(in<int>, inout<string>) test_func;
TestService ()
: Service ("TestService")
{
test1.setName ("test1");
this->registerMethod (&test1);
test2.setName ("test2");
this->registerMethod (&test2);
test_func.setName ("test_func");
this->registerMethod (&test3);
}
};
还是上面提到的,C++给我们带来的麻烦。这次需要另一组宏来完成它:
METHOD_D (void(in<int>, in<int>), test1)
METHOD_D (int(in<int>, out<int>), test2)
METHOD_D (int(in<int>, inout<string>), test_func)
BEGIN_DEFINE_D (TestService)
METHOD_DEFINE_D (void(in<int>, in<int>), test1)
METHOD_DEFINE_D(int(in<int>, out<int>), test2)
METHOD_DEFINE_D(int(in<int>, inout<string>), test_func)
END_DEFINE_D ()
END_SERVICE_D ()
METHOD*和METHOD_DEFINE*宏的参数都有一些多余的信息,没有去掉是因为放在一起容易看到写错的地方。(这个技巧来源于前几天看的一篇BLOG,很报歉没有记下地址)
3、使用的问题。
如何才能比较方便地使用?我考虑了下面这种方式:
struct IProxy;
template <class T>
struct SOAPProxy;
SOAPProxy <TestService> service;
service.connect (5000, "localhost");
int a=0;
int *n = &a;
service.test1 (3, n);
service.test1 (3, *n);
service.test2 (3, n);
service.test2 (3, *n);
service.test2 (3, NONE);
//
Method::operator ()的各个参数都将可以接受相容的类型,像上面一样,因为在TestService中我们已经定义了它要传输的值的类型。
a.NONE是什么?其实是为异步调用考虑的。假如指定某个OUT参数为NONE,则这个参数的值并不真正的OUT,而是保存在Method中。实际上Method中保存每个参数的值。
b.Method与Service如何发生关系?
从TestService的定义中我们知道,Method向Service注册自己以实现自省,但它同时也会保存Service的指向。
我们的Proxy实际上是一个继承模板,上面并没有把它指出来。它的定义是:
class XProxy : public T<xproxy>
{
//
};
所以我们的TestService其实也是模板类,它将使用XProxy中定义的序列化类。XProxy将实现Service基类中序列化虚函数以及调用虚函数。
当一个Method调用时,它会调用Service的序列化,由于被重写了,所以调用的是XProxy中的序列化方法。这个方法会把这个Method的各in/inout参数序列化,然后执行远程调用,再把调用结果反序列化给inout/out参数。
4、其它想法。
在考虑上面的定义方式时,我也考虑了其它方式,主要是返回值处理的方法,简述如下。
前面我们假设了一段将被开放为远程服务的代码:
{
void test1 (/*in*/ int v1, /*in*/ int* v2);
int test2 (/*in*/ int& v1, /*out*/ int* v2);
};
int test_func (/*in*/ int* v1, /*inout*/ string* v2);
在前面的做法中,我们的服务描述是放在那一组宏里面,好处是不用改这段代码,坏处就是代码定义的地方和描述不在一起,协调可能会有一些不便。
我也考虑了另一种做法:
{
idl <void(in<int>, in<int>)> test1 (int v1, int* v2);
idl <int(in<int>, out<int>)> test2 (int& v1, int* v2);
};
idl <int(in<int>, inout<string>) test_func int* v1, string* v2);
对于实现代码,只需要修改返回值为void的函数,把return;修改为return VOID;,并且为没有写此语句的分支加上此句。
VOID是一个特殊类型的静态变量,专为void返回值的函数设定。
这种做法修改了原有的代码,不过在定义服务时可以节省一些工作:
METHOD (test1, &Test::test1)
METHOD (test2, &Test::test2)
METHOD (test_func, test_func)
BEGIN_DEFINE (TestService)
METHOD_DEFINE (test1, &Test::test1)
METHOD_DEFINE (test2, &Test::test2)
METHOD_DEFINE (test_func, test_func)
END_DEFINE ()
END_SERVICE ()
它所需要的函数类型,将由函数指针推导。
在G++编译器下,可以使用typeof来获得函数指针的类型而不需要真得获得函数指针值,不过目前仅仅在G++下可用。(顺便说一下,typeof已经列入c++0x)
最终我放弃了这个想法,毕竟它要修改现有的代码,某些情况下这是不可能的,而且typeof目前也不能跨编译器。
三、实现。
老实说我现在还没有一份完整的或半完整的实现,大部分想法还在头脑中,测试代码倒是写了不少,主要是用来测试上述想法能否实现,我想大部分情况都已经测试了,只需要有时间来把它实现出来。
这是我近期要做的事之一,争取月内把它做完罢。
发表评论
-
Cilk++,XL
2009-08-05 10:04 2710刚看到CSDN新闻:Intel获得Cilk++技术 多核处理器 ... -
关于内存管理的一点想法
2009-07-14 16:11 1779分布式轻量级线程框架(还没取名)最近几个修改: 1、消息对象采 ... -
增加了monitor_node功能
2009-07-13 14:57 1835给分布式框架增加了类似 erlang 的 monitor_no ... -
轻量级线程切换效率
2009-07-13 12:07 2472同事测试了libcoro,它的linux版本可以使用4种模式, ... -
Cache Pool 架构
2009-06-16 10:05 3270先比较一下Hadoop。 Hadoop 架构: Cach ... -
高可用性Cache池
2009-06-15 16:10 4368前段时间开发上线了一个Cache池,使用双层Cache池冗余, ... -
抛开析构函数
2007-08-15 22:19 3408内存管理通常指的是堆 ... -
C++程序设计
2007-03-25 13:37 104上周在修改扩充同事的代码,发现几个问题。 1、访问级别几乎全 ... -
突发奇想续
2006-12-13 09:50 1963简单写了点代码,把那个方程组生成树结构: #include ... -
为C++实现一个IDL (一)
2005-09-17 19:40 3002前面简单写了点静态结构,这一次将主要关注动态模型以及调用 ... -
正式建立asgard项目 (因ancients已经被人使用了)
2005-09-20 10:30 1898“为C++实现一个IDL” ... -
为C++实现一个IDL (二)
2005-09-20 22:34 2422说明:要看懂后面那部分代码,即使用Typelist的部分 ... -
为C++实现一个IDL (三)
2005-09-21 20:34 2725一、修正错误。首先修正第二篇中的一些错误,错误的内容可见 ... -
为C++实现一个IDL (四)
2005-09-22 19:13 2049如《为C++实现一个IDL(三)》一文中所说,还剩最后一 ... -
asgard项目遗留问题 (2005-09-27更新)
2005-09-24 17:00 1815asgard项目已经准备了 ... -
C++实现简单的类型库
2005-09-26 17:31 3003很久以前看到有人问“如何在C++中实现动态加载类”时,简 ... -
为C++实现一个IDL (五)
2005-09-28 22:57 2070本篇没什么清晰的目的,只是解释一下前面的几个问题,并提出 ... -
自己写的一个max函数
2005-12-12 10:45 1929CSDN上看到有人问能否实现一个效率较高的max函数,效 ... -
C++之AOP
2005-12-15 15:43 5763AOP是近年炒得很热,但却用得很少的一门技术,不过这并不 ... -
[C++之AOP]实战Aspect C++之检查内存泄漏
2005-12-16 22:38 2741前面简单介绍了Aspect C++,相信没人看出它有什么 ...
相关推荐
tools C++语言框架IDL工具的源码实现 util C++语言框架基础工具库的源码实现 examples C++语言框架的示例代码,包括:快速入门示例、promise编程入门示例、压测程序示例 unittest tars cpp rpc框架的单元测试用例,...
C++ 11映射试图避免限制ORB开发人员的实现自由。对于每个OMG IDL构造,C++ 11映射解释使用C++ 11的构造的语法和语义。如果客户机或服务器程序使用C++ 11映射子句中所描述的结构,则符合此映射(是C++ 11)。
IDL实现坐标变换的小程序,对平面坐标系进行各种设置与改变,包括改变窗口颜色、一个窗口显示多个坐标系、坐标轴的标题设置、设置坐标轴范围及刻度数、添加注释线、改变注释字号等。
IDL精髓.pdf COM idl C++
使用IDL语言实现的图像旋转程序,别的语言也可以借鉴思路
IDL调用ENVI库函数实现非监督分类的代码
基于IDL和Visual_C++的混合编程,望对大家有一定的用途!
IDL实现的主成分分析变换,可以计算相关性矩阵,特征值和特征向量
遥感:IDL语言实现间接法图像旋转,适合初学者,无斑点噪声
一个IDL程序代码,我在IDL7.0上运行过,可以使用,大家可以试试
VC++调用IDL的使用案例 有多个IDL和VC相互调用的案例 打包在一个文件夹中
利用IDL 实现MNF的正运算,并且实现了文件的批处理
Calling C and C++ from IDL复印版,还挺清楚的。
本书向读者提供了IDL的详细描述及如何使用IDL方面的知识,基于示例、由浅入深地阐述了各种IDL...第二部分的4个章节则提供了一个IDL类型、修饰符、关键字及属性的参考。 本书适合使用COM、微软事务服务器(MTS)、C++或
通过idl语言读入txt文档,实现画图,程序为原创
总之,本书为不喜欢读教科书并能通过例子学得最好的人全面介绍IDL的精髓。本书在IDL编程技术和技巧方面只做了简要概略,而这些技术只能通过练习获取。最根本的是,这是一本笔者在学习IDL时所期望的书。
对学习IDL有很大的帮助,IDL入门教程一.doc,IDL入门教程二(上)(简单图形显示II).doc,IDL入门教程二(下)(简单图形显示I).doc,IDL入门教程三(上).doc,IDL入门教程三(下).doc,IDL入门教程四(图形显示技术).doc,IDL入门...
IDL实现快速大气校正;envi5.3 包括pro文件代码和备份的防止pro格式乱码的txt文件 主要调用ENVITask('QUAC')实现大气校正
适合初学者,很好理解
IDL影像旋转程序