一、the slice language
- 基础类型的string 对应于c++里的std::string
- module对应与c++的namespace,注意首字母大写
- 可以定义常量 const string aa="aaa";
- 自定义类型 struct 中只包含基础类型成员.
- interface
- interface主要用于client的调用,所以应该只含有操作,不能定义类型,异常和数据成员。
- 参数中从client到server是input参数,从server到client是output参数。
interface CircadianRhythm {
void setSleepPeriod(TimeOfDay startTime, TimeOfDay stopTime);
void getSleepPeriod(out TimeOfDay startTime,out TimeOfDay stopTime);
}; - 如果同时存在入参和出参,则出参排入参后
void getSleepPeriod(TimeOfDay startTime,out TimeOfDay stopTime);
当有多个出参时,可以封装到一个结构中,返回值为void.
- 不存在既是入参也是出参的参数。
- interface中的操作不允许重名。
-
nonmutating 表示只读操作,idempotent表示多次执行此操作不会改变server的状态. 为了更积极的容错,建议加这两个关键字(http://blog.csdn.net/biexf/article/details/6087441)
interface Clock { nonmutating TimeOfDay getTime(); idempotent void setTime(TimeOfDay time); };
-
interface支持继承,多继承 interface a extends b,c {}; //从b,c中继承的操作不能有重名 所有interface的公共base interface是 Object。interface与 产生的Prx相关联的,ObjectPrx是所有proxy的基类, 例:ClockPrx的基类是ObjectPrx,slice2cpp中生成的类的公共基类是::Ice::Object
- proxy中含有指针语义,所以可以定义自引用接口
interface Link {
idempotent SomeType getValue();
idempotent Link* next();
};
The Link interface contains a next operation that returns a proxy to a Link interface. Obviously, this can be used to create a chain of interfaces; the final link
in the chain returns a null proxy from its next operation.
- exception
分为 用户自定义异常 和 运行时异常.
- 用户自定义异常。 自定义异常支持继承
exception ErrorBase {
string reason;
};
enum RTError {
DivideByZero, NegativeRoot, IllegalNull /* ... */
};
exception RuntimeError extends ErrorBase {
RTError err;
};
抛出异常
interface Clock {
idempotent TimeOfDay getTime();
idempotent void setTime(TimeOfDay time) throws RangeError, Error;
};- Ice::Exception 是所有异常类的基类,用户自定义异常的基类Ice::UserException., 运行时异常Ice::LocalException
7. 在服务端一个objectadapter占用一个端口,在每个objectadapter中可以放置多个servant. 每个servant都可独立完成不用的功能. 每个一个servant都有唯一一个identity (一个字符串)作为标识。所以客户端产生一个指定具体功能的proxy 需要提供identity, 协议类型,监听ip和 监听端口,如:SimplePrinter:tcp -h 10.3.18.163 -p 10000。此proxy主要表示server的资源,所以即使在其它机器上通过此proxy调用,结果一致。对proxy的打印 :clock -t:tcp -h 10.3.18.163 -p 10000
8. client和server在进行数据交互,除了基本数据,用户定义数据类型外,还可以是proxy, 在获取某个servant的proxy后,可以直接进行对该servant的方法的调用,参见test2
9. class
- class 允许成员为空,struct不可已。当class中只包含成员变量时,作用与struct相同,但class优点是可以继承。class 只支持单继承,struct不支持。
class 中可以有操作,struct不可已。class支持自引用.
建议少用class 除非有必要理由,用class会消耗更多的资源。若在在开发中尽量用struct+interface来搞定问题,除非有足够的里有用class
二、 icebox
- 一个ice 程序框架。用一个icebox server同一管理多个icebox服务,有点如下:
- 被同一IceBox加载的Ice服务可以通过配置来获得Ice性能优化的好处,举个例子:如果一个应用是另外一个Ice服务的Client,同时client和server都在同一个IceBox里被配置,那么客户端和服务端之间的执行可以获得优化;
- 应用的不同服务(Service)之间的组合是通过IceBox的配置来完成,而不是通过硬编码(Compiling and Linking),这样可以对Server中的服务(Service)进行解耦,允许服务(Service)本身根据需要组合或者分离;
- IceBox支持在IceGrid(the server activation and deployment service)中的集成;
- 应用组件可以用动态链接库的形式发布而不是一个进程的形式发布。这就减轻了系统的负载。例如,你可以在一个JVM中运行若干个应用组件而不是有多个进程,每一个进程都有自己的JVM;
- IceBox中配置的Ice服务需要继承实现IceBox.Service接口,这样就为开发者提供了一种通用的开发框架和一个集中的管理设备;
- 被同一IceBox加载的Ice服务可以通过配置来获得Ice性能优化的好处,举个例子:如果一个应用是另外一个Ice服务的Client,同时client和server都在同一个IceBox里被配置,那么客户端和服务端之间的执行可以获得优化;
- 参见icebox的test代码,一个icebox进程是一个icebox server,这个server中可存在多个服务,在一个服务中只包含一个objectadapter, 一个objectadapter中包含多个servant.
- 一个服务的启动,nohup icebox --IceBox.Service.mmmm=HelloWorld:create --mmmm.Endpoints="tcp -p 10001" > test.log 2>&1 &。其中mmmm作为了objectadapter的名称。 endpoints指定了这个服务adapter的地址。
IceBox.Service.name=entry_point [args] //name 在一个icebox server中唯一
- 一个icebox server中启动多个服务, nohup icebox --IceBox.Service.mmmm=HelloWorld:create --mmmm.Endpoints="tcp -p 10001" --IceBox.Service.nnnn=HelloWorld:create --nnnn.Endpoints="tcp -p 10002" > test.log 2>& 1 &。
这个对应与上第四点,多个服务存在于一个进程中。
- 一个服务的启动,nohup icebox --IceBox.Service.mmmm=HelloWorld:create --mmmm.Endpoints="tcp -p 10001" > test.log 2>&1 &。其中mmmm作为了objectadapter的名称。 endpoints指定了这个服务adapter的地址。
- icebox server提供了一些管理功能,详见文档
三、 icegrid
- icegrid 结构:一个icegrid结构由 一个registry和一些node组成,通常每一个node在一个主机上,由于registry消耗的资源较少,通常将registry和node放在一起,不过实际证明这是不可取的。每个node都负责启动并监控分配给它的server进程,在server进程中包含具体的多个应用。例如:node上的一个icebox server进程,这个icebox server中可包含多个有具体应用的服务 service。每个服务service中可存在一个object adapter,这个名称必须在registry注册中唯一
client把服务信息(object和object adapter唯一标识)传给registry, registry将它转换为endpoint返给client,client通过这个endpoint建立连接。client和server在初次连接时通过registry,后续交互时,client通过endpoint直接连接。如果发现无法联通,client就会再次查询registry。 - 参见示例 BasicGrid, 这个模式是最简单的间接代理模式,不需要用部署,直接启动server连接registry注册。
一、启动流程
1. 启动registry
icegridregistry --Ice.Config=config/icegridregistry.cfg
2. 启动server
src/server/server --Ice.Config=config/server.cfg
3. 启动client完成调用
src/client/client --Ice.Config=config/client.cfg
二、配置文件说明
1.icegridregistry.cfg
a. IceGrid.Registry.Client.Endpoints=tcp -p 4061 -h localhost
最终要的是这个,server和client 通过这个ip和port连接到registry进行相应活动的请求
b. IceGrid.Registry.DynamicRegistration=1
icegrid默认情况下,是不允许objectadapter不经过部署直接注册到registry,如果这个值设成1就可以.
如果设成0,server直接注册,返回Ice::NotRegisteredException: no object adapter with id `clientadapter' is registered.
2. server.cfg
a. Ice.Default.Locator=XNTalk/Locator:tcp -h localhost -p 4061
server通过这个配置去连接registry
b. SimplePrinter.AdapterId=clientadapter
SimplePrinter是objectadapter的名称,clientadapter是 client访问的adapter,代码Ice::ObjectPrx base = ic->stringToProxy("Hello@clientadapter");
设置这个项会使objectadapter不在创建直接代理,而是创建一个可用registry解析的间接代理. clientdadapter必须在registry范围内唯一。
c. SimplePrinter.Endpoints=tcp
设置objectadapter的监听方式,ip是本机,port由registry分配
3. client.cfg
a. Ice.Default.Locator=XNTalk/Locator:tcp -h localhost -p 4061
client通过这个配置去连接registry
三、补充
在直接连接模式下,client通过servent+tcp/udp+ip+port,完成对server的连接。
在间接的模式下,通过servent+ objectadapter名 完成调用服务的定位 - 参见 AppGrid,带部署功能的icegrid,服务逻辑是可执行程序。
一、步骤
1. 配置 descriptor
2. 启动registry
icegridregistry --Ice.Config=config/icegridregistry.cfg
3. 启动node
icegridnode --Ice.Config=config/icegridnode.cfg
4. admin 部署服务
icegridadmin --Ice.Config=icegridadmin.cfg
a. 执行 application add config/application.xml
5. 启动client进行访问服务
src/client/client --Ice.Config=config/client.cfg
二、说明
1.
<icegrid>
<application name="XNTalk">
<node name="node1">
<server id="SimplePrinterServer" exe="src/server/server" activation="on-demand">
<adapter name="SimplePrinter" id="clientadapter" endpoints="tcp" />
</server>
</node>
</application>
</icegrid>
a. node 名称最好用抽象名,不要用机器名等,在一台主机上可以部署多个node,但在典型的配置中不会这么做。
b. 在一个node下可以有多个server. icegridadmin下 server list可以展示
c. 在一个server下可以有多个object adapter,name 是object adapter在server端的创建名称,id是oa在registry的注册名称.
如果id 属性存在,则在一个registry下注册的 oa的名称必须唯一, client也通过这个名称定位。Ice::ObjectPrx base = ic->stringToProxy("Hello@clientadapter");
如果id 属性不存在,则client可以通过servant@server_id.adater_name访问,只要server_id.adater_name唯一即可。访问方式
Ice::ObjectPrx base = ic->stringToProxy("Hello@SimplePrinterServer.SimplePrinter"); 一个叫常用的方式server_id在变化,adapter_name固定。
只要存在id,这种访问方式就会失败.
2. icegridregistry
a. IceGrid.Registry.Client.Endpoints=tcp -p 4061 -h localhost 提供访问监听的端口
b. IceGrid.Registry.Data=registry registry的数据库目录,必须在启动前创建
3. icegridnode
a. Ice.Default.Locator=XNTalk/Locator:tcp -h localhost -p 4061
b. IceGrid.Node.Name=node1 名称必须唯一
c. IceGrid.Node.Data=node node的数据库目录
d. IceGrid.Registry.Server.Endpoints=tcp 这个配置写错了,node 连不上
e. IceGrid.Registry.Internal.Endpoints=tcp
4. icegridadmin
Ice.Default.Locator=XNTalk/Locator:tcp -h localhost -p 4061
5. client
a. Ice.Default.Locator=XNTalk/Locator:tcp -h localhost -p 4061
b. 在同一个服务布多份时,两种descriptor配置方式,adapter的name是不变的,只有server和adapter的id在变,在client端基本采用下列
string adapter;
if ((rand() % 2) == 0)
adapter = "EncoderServer1.EncoderAdapter";
else
adapter = "EncoderServer2.EncoderAdapter";
Ice::ObjectPrx proxy = communicator->stringToProxy("factory@" + adapter); - 参见IceboxGrid,带部署功能的icegrid,服务逻辑是so。
一、步骤
1. 配置 descriptor
2. 启动registry
icegridregistry --Ice.Config=config/icegridregistry.cfg
3. 启动node
icegridnode --Ice.Config=config/icegridnode.cfg
4. admin 部署服务
icegridadmin --Ice.Config=icegridadmin.cfg
a. 执行 application add config/application.xml
5. 启动client进行访问服务
src/client/client --Ice.Config=config/client.cfg
二、说明
1.
<icegrid>
<application name="XNTalk">
<node name="node1">
<icebox id="IceBoxServer" exe="icebox" activation="on-demand">
<env>LD_LIBRARY_PATH=src/server:$LD_LIBRARY_PATH</env>
<service name="HelloService" entry="HelloService:create">
<adapter id="dingding" name="${service}" endpoints="tcp"/>
</service>
</icebox>
</node>
</application>
</icegrid>
a. node 名称最好用抽象名,不要用机器名等,在一台主机上可以部署多个node,但在典型的配置中不会这么做。
b. 在一个node下可以有多个icebox server. icegridadmin下 server list可以展示
c. 在一个icebox下可以有多个service。每个service对应一个so文件,每个service中可以存在多个object adapter。
name 是object adapter在server端的创建名称,id是oa在registry的注册名称.在一个registry下注册的 oa的名称必须唯一, client也通过这个名称定位。
Ice::ObjectPrx base = ic->stringToProxy("Hello@dingding");
如果id 属性不存在,在object adapter在registry中的注册名称icebox_id+service_name+adapter_name. client的方式方式
Ice::ObjectPrx base = ic->stringToProxy("Hello@IceBoxServer.HelloService.HelloService");
2. icegridregistry
a. IceGrid.Registry.Client.Endpoints=tcp -p 4061 -h localhost 提供访问监听的端口
b. IceGrid.Registry.Data=registry registry的数据库目录,必须在启动前创建
3. icegridnode
a. Ice.Default.Locator=XNTalk/Locator:tcp -h localhost -p 4061
b. IceGrid.Node.Name=node1 名称必须唯一
c. IceGrid.Node.Data=node node的数据库目录
4. icegridadmin
Ice.Default.Locator=XNTalk/Locator:tcp -h localhost -p 4061
5. client
a. Ice.Default.Locator=XNTalk/Locator:tcp -h localhost -p 4061
b. 在同一个服务布多份时,两种descriptor配置方式,adapter的name是不变的,只有server和adapter的id在变,在client端基本采用下列
string adapter;
if ((rand() % 2) == 0)
adapter = "EncoderServer1.EncoderAdapter";
else
adapter = "EncoderServer2.EncoderAdapter";
Ice::ObjectPrx proxy = communicator->stringToProxy("factory@" + adapter);
三、补充
1. client在间接代理通过object+ object adapter名来定位,所以如果有id属性保证adapter_id唯一,如果id不存在 保证server_id.adapter_name唯一即可访问,
以在reigstry中查到的object adapter名称为准.
2. server唯一一个object adapter的逻辑容器出现。