ICE 基础入门个人整理资料.docx
- 文档编号:24597709
- 上传时间:2023-05-29
- 格式:DOCX
- 页数:33
- 大小:27.81KB
ICE 基础入门个人整理资料.docx
《ICE 基础入门个人整理资料.docx》由会员分享,可在线阅读,更多相关《ICE 基础入门个人整理资料.docx(33页珍藏版)》请在冰豆网上搜索。
ICE基础入门个人整理资料
ICE基础入门个人整理资料
ICE自定义了一种Slice语言,目的是定义接口,作用主要应该是保持对象调用或者数据传输时的语言无关性。
开发一个ICE应用程序可以分为三步:
1.写一个Slice定义,并且编译它
2.写服务端,并编译它
3.写客户端,并编译它
1.写一个Slice定义,并且编译它:
文件Printer.ice.
moduleDemo{
interfacePrinter{
voidprintString(strings);
};
};
这个文件很简单,但需要注意,在区分大小写的系统上,扩展名一定是小写.
编译也很简单,首先确认你已将你的bin目录加到系统的环境变量Path中.然后把上面这个片断保存成Printer.ice,最后执行slice2cppPrinter.ice,执行后的结果应该是自动生成了printer.h和printer.cpp.
2.写服务端,并编译它
文件server.cpp.
#include
#include"../print.h"
usingnamespacestd;
usingnamespaceDemo;
classPrinterI:
publicPrinter{
public:
virtualvoidprintString(conststring&s,constIce:
:
Current&);
};
voidPrinterI:
:
printString(conststring&s,constIce:
:
Current&)
{
cout<
}
intmain(intargc,char*argv[])
{
intstatus=0;
Ice:
:
CommunicatorPtric;
try{
ic=Ice:
:
initialize(argc,argv);
Ice:
:
ObjectAdapterPtradapter
=ic->createObjectAdapterWithEndpoints(
"SimplePrinterAdapter","default-p10000");
Ice:
:
ObjectPtrobject=newPrinterI;
adapter->add(object,
Ice:
:
stringToIdentity("SimplePrinter"));
adapter->activate();
ic->waitForShutdown();
}catch(constIce:
:
Exception&e){
cerr< status=1; }catch(constchar*msg){ cerr< status=1; } if(ic){ try{ ic->destroy(); }catch(constIce: : Exception&e){ cerr< status=1; } } returnstatus; } 以VS2003的配置为例 1.把ice的include加入VC7.1的引用文件目录,把ice的lib目录加入VC7.1的库文件目录。 然后再把安装目录下的bin文件夹添加到系统的环境变量Path中,最后,把bin文件夹下的所有DLL文件都Copy到Windows安装目录下的System32文件夹下(win98下是System文件夹? )(当然,DLL文件的问题也可以通过修改环境变量来解决,不过是那个变量呢? Whocantellme? ) 2.新建一个C++的Win32的命令台控制程序,并且设置为空项目,把server.cpp,printer.cpp和printer.h加入这个项目(printer.cpp和printer.h放在项目的目录的外一层目录) 3.项目-》属性-》C/C++-》代码生成-》运行时库-》/MD(realse版)或/MDd(debug版) 项目-》配置属性-》C/C++-》语言-》启用运行时类型信息/GR开启 设置: 项目-》属性-》链接器-》输入-》加入iced.libiceutild.lib,此处一定要把realse库和debug库分清,debug库后有个d 4.修改printer.cpp中的#include 5.OK,编译 3.写客户端,并编译它 文件client.cpp. #include #include"../print.h" usingnamespacestd; usingnamespaceDemo; intmain(intargc,char*argv[]) { intstatus=0; Ice: : CommunicatorPtric; try{ ic=Ice: : initialize(argc,argv); Ice: : ObjectPrxbase=ic->stringToProxy( "SimplePrinter: default-p10000"); PrinterPrxprinter=PrinterPrx: : checkedCast(base); if(! printer) throw"Invalidproxy"; printer->printString("HelloWorld! "); }catch(constIce: : Exception&ex){ cerr< status=1; }catch(constchar*msg){ cerr< status=1; } if(ic) ic->destroy(); returnstatus; } 添加一个新项目到当前解决方案,按照上面的方法,对client再一次进行设置。 在解决方案管理器的解决方案上点击右键,选择批生成Debug版本,然到用资源管理器到两个解决方案的目录下的Debug文件夹中执行生产的可执行文件。 先运行server.exe,然后运行client.exe,哈哈,是不是在server.exe的窗口里出现了HelloWorld! (运行一次client.exe,出现一条) 初读代码 这一节大部分内容整理自ICE中文手册,在这里我特别感谢马维达同志的翻译给我们的学习带来了方便。 读服务端代码 文件server.cpp. #include #include"../print.h" usingnamespacestd; usingnamespaceDemo; //惯例,用后缀I表示这个类实现一个接口 classPrinterI: publicPrinter{ public: virtualvoidprintString(conststring&s,constIce: : Current&); }; /* 打开print.h,看看PrinterI父类的定义 namespaceDemo{ classPrinter: virtualpublicIce: : Object{ public: //纯虚函数,不能实例化 virtualvoidprintString(conststd: : string&, //第二个参数有缺省值,实现中可以不使用 constIce: : Current&=Ice: : Current())=0; }; }; */ voidPrinterI: : printString(conststring&s,constIce: : Current&) { cout< } intmain(intargc,char*argv[]) { //程序的退出时的状态,就是否成功执行 intstatus=0; //来包含Iceruntime的主句柄(mainhandle) Ice: : CommunicatorPtric; try{ //初始化Iceruntime(argc和argv是runtime命令参数; //就这个例子而言,服务器不需要任何命令行参数)。 //initialize返回一个指向Ice: : Communicator对象的智能指针, //这个指针是Iceruntime的主句柄。 ic=Ice: : initialize(argc,argv); //调用Communicator实例上的createObjectAdapterWithEndpoints, //创建一个对象适配器(比如: 网卡就是一种适配器)。 //参数是"SimplePrinterAdapter"(适配器的名字) //和"default-p10000"(用缺省协议(TCP/IP),侦听端口10000的请求。 ) //显然,在应用中硬编码对象标识和端口号,是一种糟糕的做法, //但它目前很有效;我们将在以后看到在架构上更加合理的做法。 Ice: : ObjectAdapterPtradapter =ic->createObjectAdapterWithEndpoints( "SimplePrinterAdapter","default-p10000"); //服务器端runtime已经初始化,实例化一个PrinterI对象, //为我们的Printer接口创建一个servant(serv服务+-ant人,背一下单词)。 Ice: : ObjectPtrobject=newPrinterI; //我们调用适配器的add,告诉它有了一个新的servant; //传给add的参数是刚才实例化的servant,再加上一个标识符。 //在这里,"SimplePrinter"串是servant的名字 //(如果我们有多个打印机,每个打印机都可以有不同的名字, //更正确的说法是,都有不同的对象标识)。 adapter->add(object, Ice: : stringToIdentity("SimplePrinter")); //调用适配器的activate方法激活适配器 //(适配器一开始是在暂停(holding)状态创建的; //这种做法在下面这样的情况下很有用: //我们有多个servant,它们共享同一个适配器, //而在所有servant实例化之前我们不想处理请求)。 //一旦适配器被激活,服务器就会开始处理来自客户的请求。 adapter->activate(); //最后,我们调用waitForShutdown。 //这个方法挂起发出调用的线程直到服务器实现终止 //——或者是通过发出一个调用关闭runtime, ic->waitForShutdown(); } catch(constIce: : Exception&e){ cerr< status=1; }catch(constchar*msg){ cerr< status=1; } if(ic){ try{ //必须调用Communicator: : destroy结束Iceruntime。 //destroy会等待任何还在运行的操作调用完成。 //此外,destroy还会确保任何还未完成的线程都得以汇合(joined), //并收回一些操作系统资源,比如文件描述符和内存。 //决不要让你的main函数不调用destroy就终止, //否则,后果无法想象。 ic->destroy(); }catch(constIce: : Exception&e){ cerr< status=1; } } returnstatus; } 注意,尽管以上的代码不算少,但它们对所有的服务器都是一样的。 你可以把这些代码放在一个辅助类里,然后就无需再为它费心了(Ice提供了这样的辅助类,叫作Ice: : Application,参见10.3.1节)。 就实际的应用代码而言,服务器只有几行代码: 六行代码定义PrinterI类,再加上三2行代码实例化一个PrinterI对象,并向对象适配器注册它。 读客户端代码 文件client.cpp. #include #include"../print.h" usingnamespacestd; usingnamespaceDemo; intmain(intargc,char*argv[]) { intstatus=0; Ice: : CommunicatorPtric; try{ ic=Ice: : initialize(argc,argv); //stringToProxy返回的代理(Proxy)类型是Ice: : ObjectPrx, //这种类型位于接口和类的继承树的根部(接口的基类)。 Ice: : ObjectPrxbase =ic->stringToProxy("SimplePrinter: default-p10000"); //但要实际要与我们的打印机交谈, //我们需要的是Printer接口、不是Object接口的代理。 //为此,需要调用PrinterPrx: : checkedCast进行向下转换(向下转型)。 //这个方法会发送一条消息给服务器, //询问“这是Printer接口的代理吗? ” //如果回答“是”,就会返回Printer的一个代理; //如果代理代表的是其他类型的接口,返回一个空代理 PrinterPrxprinter=PrinterPrx: : checkedCast(base); //测试向下转型是否成功,若不成功,就抛出出错消息并终止客户。 if(! printer)throw"Invalidproxy"; //现在,我们在我们的地址空间里有了一个激活的代理, //可以调用printString方法, //把享誉已久的"HelloWorld! "串传给它。 //服务器会在它的终端上打印这个串。 printer->printString("HelloWorld! "); } catch(constIce: : Exception&ex){ cerr< status=1; }catch(constchar*msg){ cerr< status=1; } if(ic) ic->destroy(); returnstatus; } 如果出现任何错误,客户会打印一条出错消息。 例如,如果我们没有先启动服务器就运行客户,我们会得到: Network.cpp: 471: Ice: : ConnectFailedException: connectfailed: Connectionrefused (由于windows下的命令行窗口在出错后会一闪就消失,不过我们可以在client.cpp的main函数的returnstatus;之前加上system("PAUSE");然后再在VS中把client设置为启动项目,重新编译,运行。 OK,可以看到结果了。 ) Slice语言 首先,请大家读ICE中文手册中的Slice语言一章。 这一部分除了model(模块),在ICE1.3中文手册中都有描述 图 2.1. ice网络编程示意图(服务器端和客户端采用同种编程语言C++) 图 2.2. ice网络编程示意图(服务器端和客户端采用不同编程语言) 基础知识 含有Slice定义的文件必须以.ice扩展名结尾,例如,Clock.ice就是一个有效的文件名。 编译器拒绝接受其他扩展名。 Slice支持#ifndef、#define、#endif,以及#include预处理指令。 它们的使用方式有严格的限制: 你只能把#ifndef、#define,以及#endif指令用于创建双包括(double-include)块。 例如: #ifndef_CLOCK_ICE #define_CLOCK_ICE //#include文件here... //定义here... #endif_CLOCK_ICE 我们强烈建议你在所有的Slice定义中使用双包括(double-include)块(所上),防止多次包括同一文件。 #include指令只能出现在Slice源文件的开头,也就是说,它们必须出现在其他所有Slice定义的前面。 此外,在使用#include指令时,只允许使用<>语法来指定文件名,不能使用""。 例如: #include #include"File2.ice"//不支持! 你不能把这些预处理指令用于其他目的,也不能使用其他的C++预处理指令(比如用/字符来连接行、token粘贴,以及宏展开,等等)。 在Slice定义里,既可以使用C的、也可以使用C++的注释风格: Slice关键字必须小写。 例如,class和dictionary都是关键字,必须按照所示方式拼写。 这个规则有两个例外: Object和LocalObject也是关键字,必须按照所示方式让首字母大写。 标识符以一个字母起头,后面可以跟任意数目的字母或数字。 Slice标识符被限制在ASCII字符范围内,不能包含非英语字母,与C++标识符不同,Slice标识符不能有下划线。 这种限制初看上去显得很苛刻,但却是必要的: 保留下划线,各种语言映射就获得了一个名字空间,不会与合法的Slice标识符发生冲突。 于是,这个名字空间可用于存放从Slice标识符派生的原生语言标识符,而不用担心其他合法的Slice标识符会碰巧与之相同,从而发生冲突。 标识符(变量名等等)是大小写不敏感的,但大小写的拼写方式必须保持一致(看了后面的话,再理解一下)。 例如,在一个作用域内,TimeOfDay和TIMEOFDAY被认为是同一个标识符。 但是,Slice要求你保持大小写的一致性。 在你引入了一个标识符之后,你必须始终一致地拼写它的大写和小写字母;否则,编译器就会将其视为非法而加以拒绝。 这条规则之所以存在,是要让Slice既能映射到忽略标识符大小写的语言,又能映射到把大小写不同的标识符当作不同标识符的语言。 (可以这样理解,变量名区分大小写,并且不可以是相同的单词) 是关键字的标识符: 你可以定义在一种或多种实现语言中是关键字的Slice标识符。 例如,switch是完全合法的Slice标识符,但也是C++和Java的关键字。 语言映射定义了一些规则来处理这样的标识符。 要解决这个问题,通常要用一个前缀来使映射后的标识符不再是关键字。 例如,Slice标识符switch被映射到C++的_cpp_switch,以及Java的_switch。 对关键字进行处理的规则可能会产生难以阅读的源码。 像native、throw,或export这样的标识符会与C++或Java(或两者)的关键字发生冲突。 为了让你和别人生活得更轻松一点,你应该避免使用是实现语言的关键字的Slice标识符。 要记住,以后Ice可能会增加除C++和Java以外的语言映射。 尽管期望你总结出所有流行的编程语言的所有关键字并不合理,你至少应该尽量避免使用常用的关键字。 使用像self、import,以及while这样的标识符肯定不是好主意。 转义的标识符: 在关键字的前面加上一个反斜线,你可以把Slice关键字用作标识符,例如: structdictionary{//错误! //... }; struct/dictionary{//OK //... }; 反斜线会改变关键字通常的含义;在前面的例子中,/dictionary被当作标识符dictionary。 转义机制之所以存在,是要让我们在以后能够在Slice中增加关键字,同时尽量减少对已有规范的影响: 如果某个已经存在的规范碰巧使用了新引入的关键字,你只需在新关键字前加上反斜线,就能够修正该规范。 注意,从风格上说,你应该避免用Slice关键字做标识符(即使反斜线转义允许你这么做)。 保留的标识符: Slice为Ice实现保留了标识符Ice及以Ice(任何大小写方式)起头的所有标识符。 例如,如果你试图定义一个名为Icecream的类型,Slice编译器会发出错误警告3。 以下面任何一种后缀结尾的Slice标识符也是保留的: Helper、Holder、Prx,以及Ptr。 Java和C++语言映射使用了这些后缀,保留它们是为了防止在生成的代码中发生冲突。 (注: ICE1.3的中文手册上没有“模块”这一部分)模块来组织一组相关的语句是为了解决名字冲突。 模块可以包含所有合法的Slice语句和子模块。 你可以用一些不常用的词来给最外层的模块命名,比如公司名、产品名等等。 moduleZeroC{ moduleClient{ //Definitionshere... }; moduleServer{ //Definitionshere... }; }; Slice要求所有的定义都是模块的一部分,比如,下面的语句就是非法的。 interfaceI{//错误: 全局空间中只可以有模块 //... }; 多个文件可以共享同一个模块,比如: moduleZeroC{ //Definitionshere...
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ICE 基础入门个人整理资料 基础 入门 个人 整理 资料