ICE开发学习总结Word文档下载推荐.docx
《ICE开发学习总结Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《ICE开发学习总结Word文档下载推荐.docx(14页珍藏版)》请在冰豆网上搜索。
![ICE开发学习总结Word文档下载推荐.docx](https://file1.bdocx.com/fileroot1/2022-12/13/55b40ef6-e40a-4d1e-86f8-f4bd3b21fd01/55b40ef6-e40a-4d1e-86f8-f4bd3b21fd011.gif)
分布式应用程序的构建主要有以下几种情况:
(1)DCOM
DCOM(分布式组件对象模型,分布式组件对象模式)是一系列微软的概念和程序接口,利用这个接口,客户端程序对象能够请求来自网络中另一台计算机上的服务器程序对象。
DCOM基于组件对象模型(COM),COM提供了一套允许同一台计算机上的客户端和服务器之间进行通信的接口(运行在Windows95或者其后的版本上)。
DCOM通过使用WindowsNT对于对称性多进程处理的高级支持功能就能轻易地将应用从一个单处理机扩展到庞大的多处理机系统上去。
DCOM本身并没有提供对这种动态重连接以及动态的方法分布化的支持,因为这样做需要对客户进程和组件之间相互作用的情况非常熟悉才行,此时组件在方法激活过程中保留了一些客户的特殊的状态信息。
DCOM最典型的应用是OPC,已经成为一套工业技术标准,目前绝大多数的工业硬件厂商出产的产品配备OPC接口。
(2)WebService
WebService是一种新的Web应用程序分支,其可以执行从简单的请求到复杂商务处理的任何功能。
一旦部署以后,其他WebService应用程序可以发现并调用它部署的服务。
因此,WebService是构造分布式、模块化应用程序和面向服务应用集成的最新技术和发展趋势。
实现的基本方式:
根据规则将程序服务对象编码成为XML对象,然后通过一种约定(RPC)实现远程调用。
WebService平台需要一套协议来实现分布式应用程序的创建。
Ø
XML和XSD:
数据的基本格式,与平台无关,任何使用WebService协议的应用程序都需要将数据格式转换成XSD
SOAP(简单对象访问协议):
用于交换XML编码信息的轻量级协议
WSDL:
WebService描述语言,用机器能阅读的方式提供的一个正式描述文档而基于XML(标准通用标记语言下的一个子集)的语言,用于描述WebService及其函数、参数和返回值。
因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的。
典型应用有:
.NET(微软):
C#
WebSphere(IBM):
JAVA
最大的缺点:
性能不高,对于实时性要求很高的行业很少考虑。
(3)ICE
ICE的产生就是源于.NET、CORBA及WEBSERVICE这些中间件的不足,它可以支持不同的系统,如WINDOWS、LINUX等,也可以支持在多种开发语言上使用,如C++、C、JAVA、RUBY、PYTHON、VB等,服务端可以是上面提到的任何一种语言实现的,客户端也可以根据自己的实际情况选择不同的语言实现,如服务端采用C语言实现,而客户端采用JAVA语言实现,底层的通讯逻辑通过ICE的封装实现,我们只需要关注业务逻辑。
1.2ICE工作方式
Ice是一种面向对象的中间件平台,这意味着Ice为构建面向对象的客户-服务器应用提供了工具、API和库支持。
要与Ice持有的对象进行通信,客户端必须持有这个对象的代理,这里的代理指的是这个对象的实例,ICE在运行时会定位到这个对象,然后寻找或激活它,再把In参数传给远程对象,再通过Out参数获取返回结果。
这里提到的代理又分为直接代理和间接代理,直接代理其内部保存有某个对象的标识,以及它的服务器的运行地址;
间接代理指的是其内部保存有某个对象的标识,以及对象适配器名(objectadaptername),间接代理没有包含寻址信息,为了正确地定位服务器,客户端在运行时会使用代理内部的对象适配器名,将其传给某个定位器服务,比如IcePack服务,然后,定位器会把适配器名当作关键字,在含有服务器地址的表中进行查找,把当前的服务器地址返回给客户。
ICE可以保证在任何的网络环境或者操作系统下,成功的调用只有一次,它在运行时会尽力的定位到远程服务器,在连接失败的情况下会做尝试性重复性连接,确实连不上的情况会给用户以提示。
客户端在调用服务端的方法时,可以采取同步或异步的方式实现,同步调用就相当于调用自己本地的方法一样,其它行为会被阻塞;
异步调用是非常有用的调用方式,如服务端需要准备的数据来自于其它异步接口,这个时候客户端就不需要等待,待服务端数据准备充份后,以消息的方式通知客户端,服务端就可以去干其它的事情了,而客户端也可以到服务端获取数据了。
ICE采用的网络协议有TCP、UDP以及SSL三种,不同于WebService,ICE在调用模式上有好几种选择方案,并且每种方案正对不同的网络协议的特性做了相应的选择。
1.3ICE开发步骤
1.使用slice语言编写通讯时使用到的数据结构和接口定义
Slice语言是用来定义客户端-服务器之间程序的公用数据结构和接口函数的,个人理解是:
用一种第三方语言来定义两种或者多种程序开发语言之间的消息接口,是为了方便实现多语言数据互通,不仅是在最终的可执行程序上,而主要是在程序代码上,通过第三方语言结合第三方工具,为多种语言的程序生成一些公共的基类和功能实现代码。
2.使用slice2XXX命令来生成基础代码
当使用slice编写完ice文件后,比如我们存为filetrans.ice这个文件。
然后就要根据开发人员使用的语言来调用slice2XX(XX可以为cpp,java,py,rb等等)命令生成对应语言的基础代码了。
比如你的客户端和服务器端使用的开发语言都是C++,那么,只需要运行命令:
slice2cppIceTest.ice
即可生成对应的代码FileTest.cpp和FileTest.h。
如果你的客户端或者服务端程序是使用java语言开发的,只需要调用生成java代码的命令
slice2javaIceTest.ice
即可,会生成相应的java代码包。
3.客户端代码编写
客户端代码的开发相对来说比较容易,在原来生成代码的基础上,再增加一个包含main函数的主线程代码,在其中按照ICE客户端代码一般的编写方式编写即可,常见的流程是,初始化ICE,创建连接对象,调用发送接口。
就完成了。
如果是带返回值的接口,还应该对返回值加以处理。
4.服务器代码编写
服务端一般的写法是,创建一个新的类,继承生成的基础代码中的接口类,然后在其中实现我们在ice文件中定义的接口对应的虚函数即可,要注意:
实现这个虚函数的过程,即是完成消息处理的过程,因此,所有跟应用层业务相关的东西都要在此处理函数中考虑到。
当客户端发送的消息到达服务器程序后,该函数会被自动调用去处理消息。
5.程序编译
客户端和服务器端程序的编译链接都需要ICE的开发库文件和动态库的支持。
对于工程代码本身而言,客户端程序的链接往往由两部分构成:
自己编写的发送部分代码编译生成的对象文件和ICE生成的代码生成的对象文件;
而服务器端程序的链接则还需要新增子类即消息处理部分代码编译后生成的对象文件。
1.4ICE开发举例
基于ICE的应用中,服务端和客户端都享有相同的通讯数据结构和函数接口,如上文提到的,服务端需要新建一个类,这个类继承基础代码文件中的基类,并且需要在新类中实现消息处理的虚函数,以完成对消息的实际处理.而客户端在填写完要发送的对象后,调用定义的接口进行处理,数据就会被传送到服务端,接着,服务端定义的与客户端调用同名的处理函数便会被调用,从而完成数据从客户端到服务端的传送和处理。
1.4.1编写ICE文件
定义如下ice文件,IceTest.ice:
1.4.2生成对应语言的代码
ICE最方便之处,在于它通过ICE文件生成不同语言的代码,把通讯和方法调用的实现都在ice的链接库和生成的代码中完成了。
因此,在开发ICE应用时,除了连接它提供的动态库之外,还应该在我们的工程代码中加入ICE文件生成的对应开发语言的代码,比如C++开发人员,需要生成的C++代码,java开发人员需要生成的java代码。
方法如下:
生成对应的C++的基础代码,用ICE自带的工具:
Slice2cppIceTest.ice
便看到了IceTest.h和IceTest.cpp
1.4.3客户端开发
客户端代码的结构在上文中已经说过了,最后要注意的就是客户端代码中有些对象的类型命名,是ICE生成的,初次应用ICE的开发人员可能会感到迷惑,知道它的来源就容易理解了。
一般来说,都是根据ice文件添加后缀生成的。
比如本文中的例子中的一个类型:
FileMessageHandlerPrx来源于IceTest.ice中的interfaceFileMessageHandler。
1.4.4服务器端开发
创建一个新的类,继承ICE生成文件中的基类,并且实现继承类中的虚函数。
具体步骤如下:
创建新的Class名为CMessageHandler,继承inerface对应的类FileMessageHandler,如下:
在CPP代码中实现消息处理函数,
具体实现参见附件中MessageHandler.cpp文件:
主线程代码(server.cpp):
当程序编译通过,运行后,从m_ic->
waitForShutdown()主线程阻塞,进程调度相当于交给ICE底层库,成为一个消息驱动型的程序,到来一个客户端的FileMessage消息时,CMessageHander类的ProcessMessage方法便会被调用。
1.4.5编译运行
如果正确安装了ICE的开发库,根据您所安装ICE的位置修改附录中代码目录下的Makefile,然后运行make进行编译,如果顺利通过的话,就可以进行运行测试了。
(1)启动server程序./server
(2)然后运行客户端程序,比如./client127.0.0.11234
(3)客户端就会向运行在127.0.0.1主机上的服务端请求。
客户端:
服务器端:
2Slice语言
2.1Slice语言简介
Slice的源文件以.ice为扩展名。
对于大小写不区分的系统(例如DOS),文件的扩展名可以大写,也可以小写,例如Click.ICE是有效的。
而对于大小写敏感的系统(如Unix),Clock.ICE是非法的(此时的扩展名应该小写)。
Slice是无格式语言,你可以使用空格、横向和纵向制表符、换行符安排你的代码布局。
Slice中语义和定义的布局没有关联。
2.1.1预处理指令
Slice支持#ifndef,#define,#endif以及#include预处理指令,有如下限制:
(1)#ifndef,#define和#endif指令的用途是创建双包含的块。
例如:
#ifndefCLOCKICE
#defineCLOCKICE
//#include指令
//定义
#endifCLOCKICE
(2)#include指令只能出现在Slice源文件的开始部位。
也就是说,#include必须出现在所有Slice定义的前面。
此外,#include指令只能使用<
>
语法来指定一个要包含的文件名称。
#include<
File1.ice>
Slice不支持用这些预处理指令做其他用途,也不支持使用C++预定义指令。
#include指令允许Slice使用其它文件中的类型定义。
Slice编译器会解析源文件中的所有代码,其中包括了#include指令指定的文件中的代码。
实际上,编译器只编译命令中指定的顶层文件并生成代码,因此你必须单独编译每一个inlcude的文件。
定义顺序:
Slice的结构,例如模块,接口或类型定义可以用任何顺序出现。
但是定义必须在使用之前声明。
2.1.2词法规则
Slice的语法规则与C++和Java很相似,除了标示符的差异。
2.1.3注释
Slice允许使用C和C++的注释风格:
/*
*C风格注释
*/
//C++风格
2.1.4关键字
Slice使用小写拼写关键字。
例如class和dictionary都是关键字。
不过有两个例外,Object和LocalObject也都是关键字,但是必须如显示的方式拼写。
2.1.5标识符
标识符以一个字母起头,后面可以跟随字符和数字。
Slice的标识符被限制在ASCII字符集内并且不支持非英语的字符。
不同于C++的标识符,Slice的标识符不能有下划线。
这个限制看起来似乎很苛刻,但是却是有必要的。
保留下划线,就让多语言的映射获取了命名空间,从而不会于合法的Slice标识符产生冲突。
2.1.6大小写敏感
标识符是大小写不敏感的,但是必须保持拼写一致。
例如TimeOfDay和TIMEOFDAY在同一个命名空间中是一样的。
但是,Slice强制拼写一致。
一旦你定义了一个标识符之后,你必须自始至终的拼写这个标识符的大小写,否则,编译器会认为这是非法的标识符。
这条规则之所以存在,是因为这样就允许Slice可以映射到大小写敏感的语言也能映射到大小写不敏感的语言。
你可以使用其他语言的关键字来定义Slice标示符,例如,switch可以用来作为Slice标识符,但是也是Java和Cplusplus的关键字。
Slice语言映射中针对每一种语言都定义了映射规则来处理这样的标识符。
例如,Slice把switch映射为Cplusplus的_cpp_stitch和Java的_switch。
2.1.7转义的标识符
你可以用过使用\符号来将Slice的关键字转换为标识符。
例如
structdictionary{//错误的定义
}
struct\dictionary{//正确的定义
\符号改变了关键字的含义。
在上面的例子中,\dictionary被当作dictionary标识符处理。
使用转义的标识符可以允许我们以后加入新的关键字,而不对当前存在的规范造成影响。
2.1.8保留的标识符
Slice将Ice以及以Ice开始的所有标识符作为保留的标识符。
例如,Icecream将会被认为是非法的标识符。
同时,Slice还将以以下标识符为后缀的标识符视为保留的标识符:
Helper
Hodler
Prx
Ptr
保留它们,主要是为了防止在生成代码时发生冲突。
2.2模块
对于大型系统来说,一个常见的问题就是全局命名空间的杂乱不堪:
随着开发进度的发展,独立系统的不断整合,命名冲突也就不断出现。
Slice提供了模块结构来缓和命名冲突。
如下的结构:
moduleMutableRealms
{
moduleWishClient{};
moduleWishServer{};
一个模块能容纳任何合法的Slice结构,包括其他的模块定义。
使用模块组织相关的定义从而避免全局命名的杂乱和减少命名冲突的可能。
Slice要求所有的定义被嵌套在模块中,这样你就不在模块之外定义一个全局的定义。
例如,下面的代码是不合法的:
interfaceI
//错误:
全局定义中只能是module
全局定义是被禁止的原因是因为某些实现语言不支持全局定义。
例如Python。
模块是可以被二次定义的。
//这里是定义
};
//也许在另一个源文件中:
//正确的,二次模块定义//更多的定义
二次定义模块对于大型项目是非常有用的:
它们允许你在几个源文件中存放一个模块的内容。
这样做的好处就是当一个开发者修改了模块的某一个部分时,只有与修改的内容相关的文件需要重新编译,而不是重新编译模块的相关的全部文件。
模块映射到编程语言的对应的定义结构。
例如,C++,C#和VB,模块映射到命名空间。
Java则是package。
IceModule(Ice模块)是Ice运行时API,除了少部分的语言特定的调用不能在Ice中表示以外,所有的都定义在Ice模块中。
换句话说,大部分的IceAPI是完全用Slice定义表达的。
这样做的好处就是一个单独的Slice定义就可以有效地定义适用所有支持语言的Ice运行时的API。
2.3Slice语言基本类型
类型
取值范围
大小
bool
False/true
没指定
byte
-128–127(0-255)
=8bits
Short
-2^15–2^15-1
=16bits
Int
-2^31–2^31-1
=32bits
Long
-2^63–2^63-1
=64bits
Float
IEEEsingle标准
Double
IEEEdouble标准
String
所有的Unicode字符
除了所有位为0的字符
注:
其中的byte类型的最大取值范围根据实际的语言决定。
当数据类型在服务器和客户端之间传递时,除了byte类型之外的数据类型都根据实际情况在变化。
一个long类型的值在从一台little-endian机器传递到bit-endian机器时会发生位变换。
类似的,string在从EBCDIC发往ASCII时也是发生变化的,也许string的字符的尺寸也发生了变化,因为不是所有的机器都使用8位的字符。
实际上,这些变化对于程序员来说都是透明的,而且会严格按照需要来变化。
整数类形(integertypes)
Slice提供了如下的整数类型:
short,16位
int,32位
long,64位
不过,这些类型在某些机器上会映射到更宽的原生类型。
需要注意的是那些无符号类型Slice并没有提供。
因为无符号类型影射到那些没有原生的无符号类型的语言相当困难,例如Java。
浮点数类型(floating-pointtypes)
浮点数类型遵循IEEE的规范。
如果一个实现语言么有支持IEEE的浮点数格式,Ice运行时会将浮点数值转换为原生浮点数表示。
字符串(strings)
Slice字符串使用Unicode字符集。
唯一的不能出现在字符串中的字符就是零字符。
Slice没有null字符串的概念。
这是因为null字符串很难映射到不直接支持null字符串概念的语言上,例如Python。
不要设计依靠一个null字符串来表示“不在那里”的语义的接口。
如果你需要表示可选的串,可以通过使用类,字符串的序列,或者一个空的字符串来表示null字符串。
布尔类型(booleans)
布尔类型的值只能由false和true。
如果语言映射时有原生布尔类型,语言映射就会使用该类型。
Byte类型(bytes)
Slice定义byte是一个至少8位的,在地址空间中传递时保证不会发生变化的类型。
保证不发生变化就允许交换二进制数据,而这些数据不会被篆改。
其他的Slice类型都会在传递过程中会被改变表达形式。