`
qiezi
  • 浏览: 490403 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

[C++之AOP]Aspect C++生成远程调用代码可能性探讨

    博客分类:
  • c++
阅读更多
C++ 0x keynote(以下简称0x)中描述了这样一个看起来不错的东西:

1、本地调用代码:
// use local object: 
X x; 
A a; 
std::string s("abc"); 
// … 
x.f(a, s); 
2、使用远程代理wrapper层:
// use remote object : 
proxy<X> x; 
x.connect("my_host"); 
A a; 
std::string s("abc"); 
// … 
x.f(a, s); 


仅使用一个包装层就完成远程调用?从目前的C++来看基本上不可能。 今天突然想到可以使用aspect c++来生成代码,因为aspect c++在生成代码时,也生成了一些简单的元信息,可以在函数里面取得函数的原型、各参数的类型等。 根据0x的描述,我编写了简单的测试代码:

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

class LoginService
{
public:
	virtual bool login (const string& name, const string& password, string& session) = 0;
	virtual void logout (const string& session) = 0;
};

class RemoteCall
{
public:
	bool connect (const char* host, unsigned short port)
	{
		cout << "connect success" << endl;
		return true;
	}
	bool send (const char* p, size_t len)
	{
		cout << "send: " << endl;
		cout << string(p, len) << endl;
		return true;
	}
	bool recv(char* p, size_t len)
	{
		return true;
	}
};

class RemoteLoginService : public LoginService, public RemoteCall
{
public:
	virtual bool login (const string& name, const string& password, string& session)
	{
		return false;
	}
	virtual void logout (const string& session)
	{
	}
};

int main(int argc, char *argv[])
{
	RemoteLoginService rls;
	rls.connect("localhost", 3957);
	string session;
	rls.login("lijie", "lijie", session);
	rls.logout(session);
	
	return 0;
}

现在的目标是加入一个方面,让RemoteLoginService具有远程调用功能。当然由于此处RemoteCall并未实现,所以只要能够把这个调用正确序列化就算完成目标。 这个方面完成后如下:
aspect Remote
{
	pointcut remote_class() = "RemoteCall";
	pointcut remote_call() = derived(remote_class()) && !remote_class();

	pointcut virtual_methods() = "% ...::%(...)";

	advice within(remote_call()) && execution(virtual_methods()): before(){
		stringstream ss;
		ss << "\tcall:" << JoinPoint::signature() << endl;
		ss << "\targuments:";
		for (size_t i=0; i<JoinPoint::args(); ++i)
		{
			string arg(tjp->argtype(i));
			if (arg.find("basic_string") != arg.npos)
			{
				ss << *(string*)tjp->arg(i) << "|";
			}
		}
		string send_str = ss.str();
		tjp->target()->send (send_str.c_str(), send_str.size());
	}

	advice within(remote_call()) && execution(virtual_methods()): after(){
		vector<char> buffer(1024, '\0');
		tjp->target()->recv (&(*buffer.begin()), buffer.size());
		// 解析接收的数据,远程调用结果写入tjp->result()指向的内存
	}
};

它匹配所有从RemoteCall上派生的类,为它的每个方法加入远程调用代码以及调用结果处理代码。 生成并编译运行,输出如下:
connect success
send:
        call:bool RemoteLoginService::login(const ::std::basic_string< char > &,const ::std::basic_string< char > &,::std::basic_string< char > &)
        arguments:lijie|lijie||
send:
        call:void RemoteLoginService::logout(const ::std::basic_string< char > &)
        arguments:|

由于完整序列化了各个参数值,第一个目标——生成远程调用代码——算是完成了。

下一个目标,考虑服务端如何编写?服务端需要开启一个服务,并注册各个服务接口。

要达到这个目标,aspect c++需要提供类、方法级别的类型及名称获取,不过aspect c++在这方面没有提供更多方便,现在只能在方法执行时获得方法的信息,它所生成的“元信息”过于简单,而且为了效率考虑都实现为各个独立的结构,结构的成员也大都是static的,所以无法使用一个合适的接口来反射,期待以后能加入这些特性。

所以这第2个目标实际上无法简单地完成,除非在服务端手工添加服务注册代码,这个部分工作量稍小,但还是可以做到的。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics