ICE 基础入门个人整理资料_第1页
ICE 基础入门个人整理资料_第2页
ICE 基础入门个人整理资料_第3页
ICE 基础入门个人整理资料_第4页
ICE 基础入门个人整理资料_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、ICE 基础入门个人整理资料ICE自定义了一种Slice语言,目的是定义接口,作用主要应该是保持对象调用或者数据传输时的语言无关性。开发一个ICE应用程序可以分为三步:1. 写一个Slice定义, 并且编译它2. 写服务端, 并编译它3. 写客户端, 并编译它1. 写一个Slice定义, 并且编译它:文件Printer.ice. module Demo interface Printer void printString(string s); ; ; 这个文件很简单, 但需要注意, 在区分大小写的系统上, 扩展名一定是小写.编译也很简单,首先确认你已将你的bin目录加到系统的环境变量Path中

2、.然后把上面这个片断保存成Printer.ice, 最后执行slice2cpp Printer.ice, 执行后的结果应该是自动生成了printer.h和printer.cpp.2. 写服务端, 并编译它文件server.cpp. #include #include ./print.h using namespace std; using namespace Demo; class PrinterI : public Printer public: virtual void printString(const string& s,const Ice:Current&); ; void Prin

3、terI:printString(const string& s, const Ice:Current&) cout s createObjectAdapterWithEndpoints( SimplePrinterAdapter, default -p 10000); Ice:ObjectPtr object = new PrinterI; adapter-add(object, Ice:stringToIdentity(SimplePrinter); adapter-activate(); ic-waitForShutdown(); catch (const Ice:Exception&

4、e) cerr e endl; status = 1; catch (const char* msg) cerr msg destroy(); catch (const Ice:Exception& e) cerr e endl; status = 1; return status; 以VS2003的配置为例1. 把ice的include加入VC7.1的引用文件目录,把ice的lib目录加入VC7.1的库文件目录。然后再把安装目录下的bin文件夹添加到系统的环境变量Path中,最后,把bin文件夹下的所有DLL文件都Copy到Windows安装目录下的System32文件夹下(win98下是S

5、ystem文件夹?)(当然,DLL文件的问题也可以通过修改环境变量来解决,不过是那个变量呢?Who can tell me?)2. 新建一个C的Win32的命令台控制程序,并且设置为空项目, 把server.cpp, printer.cpp和printer.h加入这个项目(printer.cpp和printer.h放在项目的目录的外一层目录)3. 项目属性C/C+ -代码生成运行时库/MD(realse版)或/MDd(debug版)项目配置属性-C/C+-语言-启用运行时类型信息/GR 开启设置:项目属性链接器输入加入iced.lib iceutild.lib,此处一定要把realse库和de

6、bug库分清, debug库后有个d4. 修改printer.cpp中的#include 为#include printer.h5. OK,编译3. 写客户端,并编译它文件client.cpp. #include #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); Ice:ObjectPrx base = ic

7、-stringToProxy( SimplePrinter:default -p 10000); PrinterPrx printer = PrinterPrx:checkedCast(base); if (!printer) throw Invalid proxy; printer-printString(Hello World!); catch (const Ice:Exception& ex) cerr ex endl; status = 1; catch (const char* msg) cerr msg destroy(); return status; 添加一个新项目到当前解决方

8、案,按照上面的方法,对client再一次进行设置。在解决方案管理器的解决方案上点击右键,选择批生成Debug版本,然到用资源管理器到两个解决方案的目录下的Debug文件夹中执行生产的可执行文件。先运行server.exe, 然后运行client.exe, 哈哈, 是不是在server.exe的窗口里出现了Hello World!(运行一次client.exe,出现一条)初读代码这一节大部分内容整理自ICE中文手册,在这里我特别感谢马维达同志的翻译给我们的学习带来了方便。读服务端代码文件server.cpp. #include #include ./print.husing namespace

9、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&,/第二个参数有缺省

10、值,实现中可以不使用const Ice:Current&= Ice:Current() = 0;*/void PrinterI:printString(const string& s, const Ice:Current&)cout s createObjectAdapterWithEndpoints(SimplePrinterAdapter, default -p 10000);/服务器端run time 已经初始化,实例化一个PrinterI 对象,/为我们的Printer 接口创建一个servant(serv 服务-ant人,背一下单词)。Ice:ObjectPtr object = n

11、ew PrinterI;/我们调用适配器的add,告诉它有了一个新的servant ;/传给add 的参数是刚才实例化的servant,再加上一个标识符。/在这里,SimplePrinter 串是servant 的名字/(如果我们有多个打印机,每个打印机都可以有不同的名字,/更正确的说法是,都有不同的对象标识)。adapter-add(object,Ice:stringToIdentity(SimplePrinter);/调用适配器的activate 方法激活适配器/(适配器一开始是在暂停(holding)状态创建的;/这种做法在下面这样的情况下很有用:/我们有多个servant,它们共享同一

12、个适配器,/而在所有servant实例化之前我们不想处理请求)。/一旦适配器被激活,服务器就会开始处理来自客户的请求。adapter-activate();/最后,我们调用waitForShutdown。/这个方法挂起发出调用的线程直到服务器实现终止/或者是通过发出一个调用关闭run time,ic-waitForShutdown();catch (const Ice:Exception& e) cerr e endl;status = 1; catch (const char* msg) cerr msg destroy(); catch (const Ice:Exception& e) c

13、err e endl;status = 1;return status;注意,尽管以上的代码不算少,但它们对所有的服务器都是一样的。你可以把这些代码放在一个辅助类里,然后就无需再为它费心了(Ice 提供了这样的辅助类,叫作Ice:Application,参见 10.3.1 节) 。就实际的应用代码而言,服务器只有几行代码:六行代码定义PrinterI 类,再加上三2 行代码实例化一个PrinterI 对象,并向对象适配器注册它。读客户端代码文件client.cpp. #include #include ./print.husing namespace std;using namespace D

14、emo;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 接口的代理。/为此,需

15、要调用PrinterPrx:checkedCast 进行向下转换(向下转型)。/这个方法会发送一条消息给服务器,/询问“这是Printer 接口的代理吗?”/如果回答“是”,就会返回Printer 的一个代理;/如果代理代表的是其他类型的接口,返回一个空代理PrinterPrx printer = PrinterPrx:checkedCast(base);/测试向下转型是否成功,若不成功,就抛出出错消息并终止客户。if (!printer) throw Invalid proxy;/现在,我们在我们的地址空间里有了一个激活的代理,/可以调用printString 方法,/把享誉已久的 Hell

16、o World! 串传给它。/服务器会在它的终端上打印这个串。printer-printString(Hello World!);catch (const Ice:Exception& ex) cerr ex endl;status = 1; catch (const char* msg) cerr msg destroy();return status;如果出现任何错误,客户会打印一条出错消息。例如,如果我们没有先启动服务器就运行客户,我们会得到:Network.cpp:471: Ice:ConnectFailedException:connect failed: Connection re

17、fused(由于windows下的命令行窗口在出错后会一闪就消失,不过我们可以在client.cpp的main函数的return status;之前加上system(PAUSE);然后再在VS2003.net中把client设置为启动项目,重新编译,运行。OK,可以看到结果了。)Slice语言首先,请大家读ICE中文手册中的Slice语言一章。 这一部分除了model(模块),在 ICE 1.3中文手册中都有描述图2.1.ice网络编程示意图(服务器端和客户端采用同种编程语言C) 图2.2.ice网络编程示意图(服务器端和客户端采用不同编程语言) 基础知识含有Slice 定义的文件必须以.ic

18、e 扩展名结尾,例如, 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)块(所上),防止多次包括

19、同一文件。#include 指令只能出现在Slice 源文件的开头,也就是说,它们必须出现在其他所有Slice 定义的前面。此外,在使用#include 指令时,只允许使用 语法来指定文件名,不能使用。例如: #include / OK#include File2.ice / 不支持!你不能把这些预处理指令用于其他目的,也不能使用其他的C+ 预处理指令 (比如用/ 字符来连接行、token 粘贴,以及宏展开,等等)。在Slice 定义里,既可以使用C 的、也可以使用C+ 的注释风格:Slice 关键字必须小写。例如, class 和dictionary 都是关键字,必须按照所示方式拼写。这个规

20、则有两个例外:Object 和LocalObject 也是关键字,必须按照所示方式让首字母大写。标识符以一个字母起头,后面可以跟任意数目的字母或数字。Slice 标识符被限制在ASCII 字符范围内,不能包含非英语字母,与C+ 标识符不同, Slice 标识符不能有下划线。这种限制初看上去显得很苛刻,但却是必要的:保留下划线,各种语言映射就获得了一个名字空间,不会与合法的Slice 标识符发生冲突。于是,这个名字空间可用于存放从Slice 标识符派生的原生语言标识符,而不用担心其他合法的Slice 标识符会碰巧与之相同,从而发生冲突 。标识符(变量名等等)是大小写不敏感的,但大小写的拼写方式必

21、须保持一致(看了后面的话,再理解一下)。例如,在一个作用域内, TimeOfDay 和TIMEOFDAY 被认为是同一个标识符。但是,Slice 要求你保持大小写的一致性。在你引入了一个标识符之后,你必须始终一致地拼写它的大写和小写字母;否则,编译器就会将其视为非法而加以拒绝。这条规则之所以存在,是要让Slice 既能映射到忽略标识符大小写的语言,又能映射到把大小写不同的标识符当作不同标识符的语言。(可以这样理解,变量名区分大小写,并且不可以是相同的单词)是关键字的标识符:你可以定义在一种或多种实现语言中是关键字的Slice 标识符。例如,switch是完全合法的Slice标识符,但也是C+和

22、Java的关键字。语言映射定义了一些规则来处理这样的标识符。要解决这个问题,通常要用一个前缀来使映射后的标识符不再是关键字。例如, Slice 标识符switch 被映射到C+ 的_cpp_switch ,以及Java 的_switch。对关键字进行处理的规则可能会产生难以阅读的源码。像native、throw,或export 这样的标识符会与C+ 或Java(或两者)的关键字发生冲突。为了让你和别人生活得更轻松一点,你应该避免使用是实现语言的关键字的Slice 标识符。要记住,以后Ice 可能会增加除C+ 和Java 以外的语言映射。尽管期望你总结出所有流行的编程语言的所有关键字并不合理,你

23、至少应该尽量避免使用常用的关键字。使用像self、import,以及while 这样的标识符肯定不是好主意。转义的标识符:在关键字的前面加上一个反斜线,你可以把Slice 关键字用作标识符,例如:struct dictionary / 错误!/ .;struct /dictionary / OK/ .;反斜线会改变关键字通常的含义;在前面的例子中, /dictionary 被当作标识符dictionary。转义机制之所以存在,是要让我们在以后能够在Slice 中增加关键字,同时尽量减少对已有规范的影响:如果某个已经存在的规范碰巧使用了新引入的关键字,你只需在新关键字前加上反斜线,就能够修正该规

24、范。注意,从风格上说,你应该避免用Slice 关键字做标识符(即使反斜线转义允许你这么做)。保留的标识符:Slice 为Ice 实现保留了标识符Ice 及以Ice (任何大小写方式)起头的所有标识符。例如,如果你试图定义一个名为Icecream 的类型, Slice 编译器会发出错误警告3。以下面任何一种后缀结尾的Slice 标识符也是保留的:Helper、Holder、Prx,以及Ptr。Java 和C+ 语言映射使用了这些后缀,保留它们是为了防止在生成的代码中发生冲突。(注:ICE 1.3的中文手册上没有“模块”这一部分)模块来组织一组相关的语句是为了解决名字冲突。模块可以包含所有合法的S

25、lice语句和子模块。你可以用一些不常用的词来给最外层的模块命名,比如公司名、产品名等等。module ZeroC module Client / Definitions here.;module Server / Definitions here.;Slice要求所有的定义都是模块的一部分,比如,下面的语句就是非法的。interface I / 错误:全局空间中只可以有模块/ .;多个文件可以共享同一个模块,比如:module ZeroC / Definitions here.;/另一个文件中 :module ZeroC / OK, reopened module/ More definit

26、ions here.;把一个大的模块放到几个文件中去可以方便编译(你只需重新编译被修改的文件,而没有必要编译整个模块)。模块将映射的语言中的相应结构,比如 C+, C#, 和 Visual Basic, Slice的modules被映射为namespaces;java中被映射为package.除了少数与特定的程序语言相关的调用之外,ice的绝大部分API(应用程序接口)都是用Slice来定义的 。这样做的好处是可以用一个ICE API定义文件来支持所有的程序语言。注意为了保证代码的简洁,以后文章中提及的Slice定义没有写出包含的模块,你要假定该语句是在一个模块中。表2.1.Slice的数据类

27、型 类型取值范围大小(单位:bit)boolfalse or true 1byte-128-127或0-255 8short215 至215 1 16int231 至231 1 32long263 至263 1 64floatIEEE的单精度 32 bitsdoubleIEEE的双精度 64 bitsstring所有Unicode 字符,除了所有位为零的字符变长用户定义的类型 枚举:enum Fruit Apple, Pear, Orange ;这个定义引入了一种名为Fruit 的类型,这是一种拥有自己权利的新类型。关于怎样把顺序值(ordinal values)赋给枚举符的问题, Slice

28、 没有作出定义。例如,你不能假定,在各种实现语言中,枚举符Orange 的值都是2。Slice 保证枚举符的顺序值会从左至右递增,所以在所有实现语言中,Apple 都比Pear 要小。与C+ 不同, Slice 不允许你控制枚举符的顺序值(因为许多实现语言不支持这种特性):enum Fruit Apple = 0, Pear = 7, Orange = 2 ; / 出错 在实践中,只要你不在地址空间之间传送枚举符的顺序值,你就不用管枚举符使用的值是多少。例如,发送值0 给服务器来表示Apple 可能会造成问题,因为服务器可能没有用0 表示Apple。相反,你应该就发送值Apple 本身。如果在

29、接收方的地址空间中, Apple 是用另外的顺序值表示的, Ice run time 会适当地翻译这个值。与在C+ 里一样, Slice 枚举符也会进入围绕它的名字空间,所以下面的定义是非法的:enum Fruit Apple, Pear, Orange ; enum ComputerBrands Apple, IBM, Sun, HP ; / Apple已经被定义! Slice 不允许定义空的枚举。 结构Slice 支持含有一个或多个有名称的成员的结构,这些成员可以具有任意类型,包括用户定义的复杂类型。例如:struct TimeOfDay short hour; / 0 - 23 shor

30、t minute; / 0 - 59 short second; / 0 - 59 ; 与在 C+ 里一样,这个定义引入了一种叫作TimeOfDay 的新类型。结构定义会形成名字空间,所以结构成员的名字只需在围绕它们的结构里是唯一的。在结构内部,只能出现数据成员定义,这些定义必须使用有名字的类型。例如,你不可能在结构内定义结构: struct TwoPoints struct Point /错误! short x; short y; ; Point coord1; Point coord2; ; 这个规则大体上适用于Slice:类型定义不能嵌套(除了模块支持嵌套)。其原因是,对于某些目标语言而

31、言,嵌套的类型定义可能会难以实现,而且,即使能够实现,也会极大地使作用域解析规则复杂化。对于像Slice 这样的规范语言而言,嵌套的类型定义并无必要你总能以下面的方式编写上面的定义(这种方式在风格上也更加整洁): struct Point short x; short y; ; struct TwoPoints / Legal (and cleaner!) Point coord1; Point coord2; 序列序列是变长的元素向量:sequence FruitPlatter; 序列可以是空的也就是说,它可以不包含元素;它也可以持有任意数量的元素,直到达到你的平台的内存限制。序列包含的元素

32、自身也可以是序列。这种设计使得你能够创建列表的列表:sequence FruitBanquet; 序列可用于构建许多种collection,比如向量、列表、队列、集合、包(bag),或是树(次序是否重要要由应用决定;如果无视次序,序列充当的就是集合和包)。序列的一种特别的用法已经成了惯用手法,即用序列来表示可选的值。例如,我们可能拥有一个Part 结构,用于记录小汽车的零件的详细资料。这个结构可以记录这样的资料:零件名称、描述、重量、价格,以及其他详细资料。 备件通常都有序列号,我们用一个long 值表示。但有些零件,比如常用的螺丝钉,常常没有序列号,那么我们在螺丝钉的序列号字段里要放进什么内

33、容?要处理这种情况,有这样一些选择:o 用一个标记值,比如零,来指示“没有序列号”的情况。这种方法是可行的,只要确实有标记值可用。尽管看起来不大可能有人把零用作零件的序列号,这并非是不可能的。而且,对于其他的值,比如温度值,在其类型的范围中的所有值都可能是合法的,因而没有标记值可用。o 把序列号的类型从long 变成string。串自己有内建的标记值,也就是空串,所以我们可以用空串来指示.“没有序列号”的情况。这也是可行的,但却会让大多数人感到不快:我们不应该为了得到一个标记值,而把某种事物自然的数据类型变成stringo 增加一个指示符来指示序列号的内容是否有效.o struct Part

34、o string name;o string description;o / .o bool serialIsValid; / true if part has serial numbero long serialNumber;o ; 对于大多数人而言,这也让人讨厌,而且最终肯定会让你遇到麻烦:迟早会有程序员忘记在使用序列号之前检查它是否有效,从而带来灾难性的后果。o 用序列来建立可选字段这种技术使用了下面的惯用手法:sequence SerialOpt; struct Part string name; string description; / . SerialOpt serialNumb

35、er; / optional: zero or one element ; 按照惯例, Opt 后缀表示这个序列是用来建立可选值的。如果序列是空的,值显然就不在那里;如果它含有一个元素,这个元素就是那个值。这种方案明显的缺点是,有人可能会把不止一个元素放入序列。为可选值增加一个专用的Slice 成分可以纠正这个问题。但可选值并非那么常用,不值得为它增加一种专门的语言特性(我们将看到,你还可以用类层次来建立可选字段)。 词典词典是从键类型到值类型的映射。例如:struct Employee long number; string firstName; string lastName; ; dic

36、tionary EmployeeMap; 这个定义创建一种叫作EmployeeMap 的词典,把雇员号映射到含有雇员详细资料的结构。你可以自行决定键类型(在这个例子中是long 类型的雇员号)是否是值类型(在这个例子中是Employee 结构)的一部分就Slice 而言,你无需让键成为值的一部分。词典可用于实现稀疏数组,或是具有非整数键类型的任何用于查找的数据结构。尽管含有键值对的结构的序列可用于创建同样的事物,词典要更为适宜:o 词典明确地表达了设计者的意图,也就是,提供从值的域(domain)到值的范围(range)的映射(含有键值对的结构的序列没有如此明确地表达同样的意图)。o 在编程语

37、言一级,序列被实现成向量(也可能是列表),也就是说,序列不大适用于内容稀疏的域,而且要定位具有特定值的元素,需要进行线性查找。而词典被实现成支持高效查找的数据结构(通常是哈希表或红黑树),其平均查找时间是O(log n),或者更好。词典的键类型无需为整型。例如,我们可以用下面的定义来翻译一周每一天的名称:o dictionary WeekdaysEnglishToGerman; 服务器实现可以用键值对MondayMontag、TuesdayDienstag,等等,对这个映射表进行初始化。o 词典的值类型可以是用户定义的任何类型。但词典的键类型只能是以下类型之一: 整型(byte、short、i

38、nt、long、bool,以及枚举类型) string 元素类型为整型或string 的序列 数据成员的类型只有整型或string 的结构复杂的嵌套类型,比如嵌套的结构或词典,以及浮点类型(float和double),不能用作键类型。之所以不允许使用复杂的嵌套类型,是因为这会使词典的语言映射复杂化;不允许使用浮点类型,是因为浮点值在跨越机器界线时,其表示会发生变化,有可能导致成问题的相等语义。 常量定义与直接量Slice 允许你定义常量。常量定义的类型必须是以下类型中的一种:o 整型(bool、byte、short、int、long,或枚举类型)o float 或doubleo string下

39、面有一些例子:const bool AppendByDefault = true; const byte LowerNibble = 0x0f; const string Advice = Dont Panic!; const short TheAnswer = 42; const double PI = 3.1416; enum Fruit Apple, Pear, Orange ; const Fruit FavoriteFruit = Pear; 直接量(literals)的语法与C+ 和Java 的一样(有一些小的例外):o 布尔常量只能用关键字false和true初始化(你不能用0和

40、1来表示false和true)。o 和C+ 一样,你可以用十进制、八进制,或十六进制方式来指定整数直接量。例如:o const byte TheAnswer = 42;o const byte TheAnswerInOctal = 052;o const byte TheAnswerInHex = 0x2A; / or 0x2a 注意如果你把byte 解释成数字、而不是位模式,你在不同的语言里可能会得到不同的结果。例如,在C+ 里, byte 映射到char,取决于目标平台, char 可能是有符号的,也可能是无符号的。注意用于指示长常量和无符号常量的后缀(C+ 使用的l、L、u、U)是非法的:const long Wrong = 0u; / Syntax error const long WrongToo = L; / Syntax error o 整数直接量的值必须落在其常量类型的范围内,否则编译器就会发出诊断消息。 浮点直接量使用的是C+语法,除了你不能用l或L后缀

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论