牵牛散步
仗剑走天涯

初读代码

这一节大部分内容整理自ICE中文手册,在这里我特别感谢马维达同志的翻译给我们的学习带来了方便。

读服务端代码

文件server.cpp. 

#include <Ice/Ice.h> 		
#include "../print.h"
using namespace std;
using namespace Demo;

//惯例,用后缀I 表示这个类实现一个接口
class PrinterI : public Printer {
public:
	virtual void printString(const string& s, const Ice::Current&);
};	 
/*
打开print.h,看看PrinterI父类的定义

namespace Demo {
class Printer : virtual public Ice::Object {
public:

//纯虚函数,不能实例化
virtual void printString(const std::string&,
//第二个参数有缺省值,实现中可以不使用
const Ice::Current&= Ice::Current()) = 0;
};
};
*/

void PrinterI::printString(const string& s, const Ice::Current&)
{
	cout << s << endl;
}

int  main(int argc, char* argv[])
{	
	//程序的退出时的状态,就是否成功执行
	int status = 0; 

	 //来包含Ice run time 的主句柄	(main handle)
	Ice::CommunicatorPtr ic;

	try {
	//初始化Ice run time (argc和argv是run time命令参数;
	//就这个例子而言,服务器不需要任何命令行参数)。
    //initialize 返回一个指向Ice::Communicator对象的智能指针,
	//这个指针是Ice run time 的主句柄。
		ic = Ice::initialize(argc, argv);
	 
	 //调用Communicator 实例上的createObjectAdapterWithEndpoints,
	 //创建一个对象适配器(比如:网卡就是一种适配器)。
	 //参数是"SimplePrinterAdapter" (适配器的名字)
	 //和"default -p 10000"(用缺省协议(TCP/IP),侦听端口10000 的请求。)
	 //显然,在应用中硬编码对象标识和端口号,是一种糟糕的做法,
	 //但它目前很有效;我们将在以后看到在架构上更加合理的做法。
		Ice::ObjectAdapterPtr adapter
			= ic->createObjectAdapterWithEndpoints(
			"SimplePrinterAdapter", "default -p 10000");

	  //服务器端run time 已经初始化,实例化一个PrinterI 对象,
	  //为我们的Printer 接口创建一个servant(serv 服务+-ant人,背一下单词)。
		Ice::ObjectPtr object = new PrinterI;

	  //我们调用适配器的add,告诉它有了一个新的servant ;
	  //传给add 的参数是刚才实例化的servant,再加上一个标识符。
	  //在这里,"SimplePrinter" 串是servant 的名字
	  //(如果我们有多个打印机,每个打印机都可以有不同的名字,
	  //更正确的说法是,都有不同的对象标识)。
		adapter->add(object,
			Ice::stringToIdentity("SimplePrinter"));

		//调用适配器的activate 方法激活适配器
		//(适配器一开始是在暂停(holding)状态创建的;
		//这种做法在下面这样的情况下很有用:
		//我们有多个servant,它们共享同一个适配器,
		//而在所有servant实例化之前我们不想处理请求)。
		//一旦适配器被激活,服务器就会开始处理来自客户的请求。
		adapter->activate();

		//最后,我们调用waitForShutdown。
		//这个方法挂起发出调用的线程直到服务器实现终止
		//——或者是通过发出一个调用关闭run time,
		ic->waitForShutdown();
	} 
	catch (const Ice::Exception& e) {
			cerr << e << endl;
		status = 1;
	} catch (const char* msg) {
		cerr << msg << endl;
		status = 1;
	}
	if (ic) {
		try {

		//必须调用Communicator::destroy结束Ice run time。
		//destroy 会等待任何还在运行的操作调用完成。
		//此外, destroy 还会确保任何还未完成的线程都得以汇合(joined),
		//并收回一些操作系统资源,比如文件描述符和内存。
		//决不要让你的main 函数不调用destroy 就终止,
		//否则,后果无法想象。
			ic->destroy();

		} catch (const Ice::Exception& e) {
			cerr << e << endl;
			status = 1;
		}
	}
	return status;
}

注意,尽管以上的代码不算少,但它们对所有的服务器都是一样的。你可以把这些代码放在一个辅助类里,然后就无需再为它费心了(Ice 提供了这样的辅助类,叫作Ice::Application,参见 10.3.1 节) 。就实际的应用代码而言,服务器只有几行代码:六行代码定义PrinterI 类,再加上三2 行代码实例化一个PrinterI 对象,并向对象适配器注册它。

读客户端代码

文件client.cpp. 

#include <Ice/Ice.h>
#include "..\print.h"
using namespace std;
using namespace Demo;
int main(int argc, char* argv[])
{
	int status = 0;
	Ice::CommunicatorPtr ic;
	try {
		ic = Ice::initialize(argc, argv);

		//stringToProxy 返回的代理(Proxy)类型是Ice::ObjectPrx,
		//这种类型位于接口和类的继承树的根部(接口的基类)。
		 Ice::ObjectPrx base 
		=ic->stringToProxy(	"SimplePrinter:default -p 10000");

		//但要实际要与我们的打印机交谈,
		//我们需要的是Printer 接口、不是Object 接口的代理。
		//为此,需要调用PrinterPrx::checkedCast 进行向下转换(向下转型)。
		//这个方法会发送一条消息给服务器,
		//询问“这是Printer 接口的代理吗?”
		//如果回答“是”,就会返回Printer 的一个代理;
		//如果代理代表的是其他类型的接口,返回一个空代理
		PrinterPrx printer = PrinterPrx::checkedCast(base);
		
		//测试向下转型是否成功,若不成功,就抛出出错消息并终止客户。
		if (!printer) 	throw "Invalid proxy";

		//现在,我们在我们的地址空间里有了一个激活的代理,
		//可以调用printString 方法,
		//把享誉已久的 "Hello World!" 串传给它。
		//服务器会在它的终端上打印这个串。
		printer->printString("Hello World!");
	}
	catch (const Ice::Exception& ex) {
		cerr << ex << endl;
		status = 1;
	} catch (const char* msg) {
		cerr << msg << endl;
		status = 1;
	}
	if (ic)
		ic->destroy();
	return status;
}

如果出现任何错误,客户会打印一条出错消息。例如,如果我们没有先启动服务器就运行客户,我们会得到:

Network.cpp:471: Ice::ConnectFailedException:
connect failed: Connection refused

(由于windows下的命令行窗口在出错后会一闪就消失,不过我们可以在client.cpp的main函数的return status;之前加上system("PAUSE");然后再在VS2003.net中把client设置为启动项目,重新编译,运行。OK,可以看到结果了。)

posted on 2005-12-13 11:58 牵牛散步 阅读(3185) 评论(0)  编辑 收藏 引用 所属分类: ICE学习资料

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理