想搞清楚slice为我们生成了什么样的框架代码,就先搞明白Ice的远程调用框架暗中为我们做了些什么?

Ice将Ice Object的方法调用分为三个阶段(或步骤),分别是begin,process和end。如下图:

或者说Ice将一次完整的Ice Object方法调用划分成上面三个阶段。基于上面的划分,又将三个阶段应用到远程调用中。其中将begin和end阶段应用在Object Proxy端,而process阶段应用在Object Servant端。远程调用实质在应用ActiveObject模式,模式有两个角色分别是代理Proxy以及主动对象ActiveObject。之所以叫主动对象,是因为对象的执行不在控制线程上,而是有自己专有的线程去执行它的方法。访问主动对象,只能通过其代理在调用方的控制线程上向主动对象发出调用请求。由于应用了ActiveObject模式,调用方和对象执行不在同一线程(,包括不同主机上的线程)。因此产生了同步和异步的问题。所以同样需要应用Future模式。而这个Future的实现就由AsyncResult来担当。

现在我们就很清楚slice会为我们生成哪些框架性的代码了。

slice为我们生成上面三阶段的框架代码,begin,process和end三个阶段。begin和end阶段的代码放在代理端(Proxy),也就是stub存根;而process阶段的代码放在饲服端(Servant),也就是skeleton骨架。

毫无疑问地,begin阶段的框架代码就是为我们完成如何将请求包装成消息包,并发送出去。end阶段的框架代码就是为我们完成如何将回来的响应拆装出结果。所以每一个接口方法,都会在stub类生成一个_iceI_begin_Method的方法,以及五个简单包装使用它的参数重载版本begin_Method的方法,一个end_Method的方法,最后还有一个调用的简易版本Method,这个简易版本的Method只是简单地在使用end_Method(begin_Method())。你也可以自行组织begin和end阶段的函数来完成一次请求。

process阶段的框架代码理所当然地会放在skeleton端。为什么叫做skeleton骨架,那看它为我们完成了什么工作。它为我们提供了一个_iceDispatch分派调用的函数,它将请求分派到目标的接口方法入口,并交给接口方法的实现体去执行调用。换句话说,每个接口方法,都会在skeleton类生成一个_iceD_Method的入口成员函数,以及一个空的Method虚成员函数。_iceD_Method为我们完成请求参数的拆装,以及输出参数的准备,然后调用Method虚成员函数,最后将结果包装成响应消息包。在这个skeleton骨架中,我们要做的就是如何去实现虚成员函数Method。我们从生成的函数名字就可以加深印象,_iceD_Method就是由_iceDispatch分派调用请求时调用到的入口,这个入口又为我们完成几个框架步骤的工作,并调用我们的实现的虚函数。

另外一点要注意,在上面说到的框架并没有涉及网络的通讯操作(发送,接收或侦听)。因为网络服务是由Communicator提供,并不是调用框架的一部分,而框架依赖的环境的一个服务。

还有一点要注意的是,返回结果和out方向的参数并不是分开特别看待的,返回结果与out方向的参数都是响应消息中的payload,请参数《ZeroC ICE的协议》,encpas部分。返回结果是默认是第一个out方向参数,我们所有定义的out方向参数都向后顺延一个位置。

每个skeleton骨架类都会为我们自动实现ice_id,ice_ids,ice_isA和ice_ping接口方法。

下面是以Ice项目包中test/acm为例的代码参考:

::Test::TestIntfPrx getTestIntf(const ::Ice::Context& context = ::Ice::noExplicitContext)
{
return end_getTestIntf(_iceI_begin_getTestIntf(context, ::IceInternal::dummyCallback, , true));
} ::Ice::AsyncResultPtr begin_getTestIntf(const ::Ice::Context& context = ::Ice::noExplicitContext)
{
return _iceI_begin_getTestIntf(context, ::IceInternal::dummyCallback, );
} ::Ice::AsyncResultPtr begin_getTestIntf(const ::Ice::CallbackPtr& del, const ::Ice::LocalObjectPtr& cookie = )
{
return _iceI_begin_getTestIntf(::Ice::noExplicitContext, del, cookie);
} ::Ice::AsyncResultPtr begin_getTestIntf(const ::Ice::Context& context, const ::Ice::CallbackPtr& del, const ::Ice::LocalObjectPtr& cookie = )
{
return _iceI_begin_getTestIntf(context, del, cookie);
} ::Ice::AsyncResultPtr begin_getTestIntf(const ::Test::Callback_RemoteObjectAdapter_getTestIntfPtr& del, const ::Ice::LocalObjectPtr& cookie = )
{
return _iceI_begin_getTestIntf(::Ice::noExplicitContext, del, cookie);
} ::Ice::AsyncResultPtr begin_getTestIntf(const ::Ice::Context& context, const ::Test::Callback_RemoteObjectAdapter_getTestIntfPtr& del, const ::Ice::LocalObjectPtr& cookie = )
{
return _iceI_begin_getTestIntf(context, del, cookie);
} ::Test::TestIntfPrx end_getTestIntf(const ::Ice::AsyncResultPtr&); private: ::Ice::AsyncResultPtr _iceI_begin_getTestIntf(const ::Ice::Context&, const ::IceInternal::CallbackBasePtr&, const ::Ice::LocalObjectPtr& cookie = , bool sync = false);

slice为stub存根生成的函数

::Ice::AsyncResultPtr
IceProxy::Test::RemoteObjectAdapter::_iceI_begin_getTestIntf(const ::Ice::Context& context, const ::IceInternal::CallbackBasePtr& del, const ::Ice::LocalObjectPtr& cookie, bool sync)
{
_checkTwowayOnly(iceC_Test_RemoteObjectAdapter_getTestIntf_name, sync);
::IceInternal::OutgoingAsyncPtr result = new ::IceInternal::CallbackOutgoing(this, iceC_Test_RemoteObjectAdapter_getTestIntf_name, del, cookie, sync);
try
{
result->prepare(iceC_Test_RemoteObjectAdapter_getTestIntf_name, ::Ice::Normal, context);
result->writeEmptyParams();
result->invoke(iceC_Test_RemoteObjectAdapter_getTestIntf_name);
}
catch(const ::Ice::Exception& ex)
{
result->abort(ex);
}
return result;
} ::Test::TestIntfPrx
IceProxy::Test::RemoteObjectAdapter::end_getTestIntf(const ::Ice::AsyncResultPtr& result)
{
::Ice::AsyncResult::check(result, this, iceC_Test_RemoteObjectAdapter_getTestIntf_name);
::Test::TestIntfPrx ret;
if(!result->waitForResponse())
{
try
{
result->throwUserException();
}
catch(const ::Ice::UserException& ex)
{
throw ::Ice::UnknownUserException(__FILE__, __LINE__, ex.ice_id());
}
}
::Ice::InputStream* istr = result->startReadParams();
istr->read(ret);
result->endReadParams();
return ret;
}

begin和end阶段的框架实现

bool
Test::RemoteObjectAdapter::_iceDispatch(::IceInternal::Incoming& in, const ::Ice::Current& current)
{
::std::pair<const ::std::string*, const ::std::string*> r = ::std::equal_range(iceC_Test_RemoteObjectAdapter_all, iceC_Test_RemoteObjectAdapter_all + , current.operation);
if(r.first == r.second)
{
throw ::Ice::OperationNotExistException(__FILE__, __LINE__, current.id, current.facet, current.operation);
} switch(r.first - iceC_Test_RemoteObjectAdapter_all)
{
case :
{
return _iceD_activate(in, current);
}
case :
{
return _iceD_deactivate(in, current);
}
case :
{
return _iceD_getTestIntf(in, current);
}
case :
{
return _iceD_hold(in, current);
}
case :
{
return _iceD_ice_id(in, current);
}
case :
{
return _iceD_ice_ids(in, current);
}
case :
{
return _iceD_ice_isA(in, current);
}
case :
{
return _iceD_ice_ping(in, current);
}
default:
{
assert(false);
throw ::Ice::OperationNotExistException(__FILE__, __LINE__, current.id, current.facet, current.operation);
}
}
} bool
Test::RemoteObjectAdapter::_iceD_getTestIntf(::IceInternal::Incoming& inS, const ::Ice::Current& current)
{
_iceCheckMode(::Ice::Normal, current.mode);
inS.readEmptyParams();
::Test::TestIntfPrx ret = this->getTestIntf(current);
::Ice::OutputStream* ostr = inS.startWriteParams();
ostr->write(ret);
inS.endWriteParams();
return false;
}

skeleton为我们完成的框架工作

class RemoteObjectAdapter : public virtual ::Ice::Object
{
public: // ... virtual ::Test::TestIntfPrx getTestIntf(const ::Ice::Current& = ::Ice::noExplicitCurrent) = ;
bool _iceD_getTestIntf(::IceInternal::Incoming&, const ::Ice::Current&); // other generated code by slice virtual bool _iceDispatch(::IceInternal::Incoming&, const ::Ice::Current&); protected: virtual void _iceWriteImpl(::Ice::OutputStream*) const;
virtual void _iceReadImpl(::Ice::InputStream*);
};

slice为skeleton骨架生成的函数

我们除了使用slice为我们生成的stub类的begin和end函数来进行Ice Object的请求调用外,还可以使用::IceProxy::Ice::object提供的通常版本ice_invoke来完成调用。ice_invoke也是分为begin和end两个阶段,分别对应有函数begin_ice_invoke以及end_ice_invoke。之所以是通用版本,是因为你必须要构建Operation对象,而且接受的参数并不是不逐个逐个地接受的,而是作为两条序列化的流。也就是说,如果使用invoke版本来进行请求调用,你必须手动完成参数的序列包装,和结果的反序列拆装。

bool
IceProxy::Ice::Object::ice_invoke(const string& operation,
OperationMode mode,
const vector<Byte>& inEncaps,
vector<Byte>& outEncaps,
const Context& context)
{
pair<const Byte*, const Byte*> inPair;
if(inEncaps.empty())
{
inPair.first = inPair.second = ;
}
else
{
inPair.first = &inEncaps[];
inPair.second = inPair.first + inEncaps.size();
}
return ice_invoke(operation, mode, inPair, outEncaps, context);
} AsyncResultPtr
IceProxy::Ice::Object::_iceI_begin_ice_invoke(const string& operation,
OperationMode mode,
const vector<Byte>& inEncaps,
const Context& ctx,
const ::IceInternal::CallbackBasePtr& del,
const ::Ice::LocalObjectPtr& cookie,
bool sync)
{
pair<const Byte*, const Byte*> inPair;
if(inEncaps.empty())
{
inPair.first = inPair.second = ;
}
else
{
inPair.first = &inEncaps[];
inPair.second = inPair.first + inEncaps.size();
}
return _iceI_begin_ice_invoke(operation, mode, inPair, ctx, del, cookie);
} bool
IceProxy::Ice::Object::end_ice_invoke(vector<Byte>& outEncaps, const AsyncResultPtr& result)
{
AsyncResult::check(result, this, ice_invoke_name);
bool ok = result->waitForResponse();
if(_reference->getMode() == Reference::ModeTwoway)
{
const Byte* v;
Int sz;
result->readParamEncaps(v, sz);
vector<Byte>(v, v + sz).swap(outEncaps);
}
return ok;
}
AsyncResultPtr
IceProxy::Ice::Object::_iceI_begin_ice_invoke(const string& operation,
OperationMode mode,
const pair<const Byte*, const Byte*>& inEncaps,
const Context& ctx,
const ::IceInternal::CallbackBasePtr& del,
const ::Ice::LocalObjectPtr& cookie,
bool sync)
{
OutgoingAsyncPtr result = new CallbackOutgoing(this, ice_invoke_name, del, cookie, sync);
try
{
result->prepare(operation, mode, ctx);
result->writeParamEncaps(inEncaps.first, static_cast<Int>(inEncaps.second - inEncaps.first));
result->invoke(operation);
}
catch(const Exception& ex)
{
result->abort(ex);
}
return result;
} bool
IceProxy::Ice::Object::_iceI_end_ice_invoke(pair<const Byte*, const Byte*>& outEncaps, const AsyncResultPtr& result)
{
AsyncResult::check(result, this, ice_invoke_name);
bool ok = result->waitForResponse();
if(_reference->getMode() == Reference::ModeTwoway)
{
Int sz;
result->readParamEncaps(outEncaps.first, sz);
outEncaps.second = outEncaps.first + sz;
}
return ok;
}

这里的inEncaps以及outEncaps的最终版本是pair<const Byte*, const Byte*>类型,其实是一个encaps数组的iter_begin以及iter_end。由于一个encaps只是stream中的一段,没有具体的固定(长度的)类型,所以一个encaps数组也就是一系列一段段的流,它的数组容器就是这一段段的流的总流。

ZeroC ICE的远程调用框架的更多相关文章

  1. ZeroC ICE的远程调用框架 Slice如何帮助我们进行Ice异步编程(AMI,AMD)

    Slice最大的用处就是为我们使用Ice进行编程,代劳绝大部分的重复性代码,并提供一些帮助性的框架代码,如用于AMI和AMD方式进行异步编程的回调框架. 当Slice不为我们生成代码时,我们仍然可以按 ...

  2. ZeroC ICE的远程调用框架 AMD

    继上一篇<ZeroC ICE的远程调用框架>,本篇再来说其中的AMD.(本篇需要重写) 当在ice文件中声明某个接口方法Method为["amd"]后,接口方法在stu ...

  3. ZeroC ICE的远程调用框架 AMI与AMD -Why?

    在Ice有两种异步使用的方式,AMI和AMD.AMI是异步方法调用,AMD是异步方法调度(分派).前者用在代理端,后者用在饲服实现端. AMI其实就是在代理端,使用Future机制进行异步调用,而不阻 ...

  4. ZeroC ICE的远程调用框架 Callback(一)-AMI异步方法调用框架

    Ice框架提供了不少回调设施,其中一些是使用Ice远程调用进行ami模式或amd模式的支撑.本篇来看一下用于代理端的回调设施. Ice代码中有好几个Callback相关命名的基类,并且slice还会为 ...

  5. ZeroC ICE的远程调用框架 class与interface

    我们在ice文件中定义的class或interface,slice都会为我们生成stub存根类和skeleton骨架类.在这里要注意slice并没有分别生成两份单独用在客户端或服务端的接口给开发分发. ...

  6. ZeroC ICE的远程调用框架 ServantLocator与Locator

    ServantLocator定位的目标是Servant,而Locator定位的目标是“Ice Object”,即一个可定位的“Ice Object”代理.Servant是::Ice::Object的继 ...

  7. ZeroC ICE的远程调用框架 ThreadPool

    ThreadPool提供Reactor/Proactor服务,并且强偶合了Reactor(反应器)/Proactor(前摄器).不同于Reactor/Proactor使用线程池 进行事件处理的设计.如 ...

  8. ZeroC ICE的远程调用框架 代理引用地址

    在官方文档中称为Binding,协议-地址对的绑定.在Proxy模式中,一般地有三个参与者,Proxy,Subject以及RealSubject.Subject定义了Proxy(代理)和RealSub ...

  9. ZeroC ICE的远程调用框架 ASM与defaultServant,ServantLocator

    ASM与defaultServant,ServantLocator都是与调用调度(Dispatch)相关的. ASM是ServantManager中的一张二维表_servantMapMap,默认Ser ...

随机推荐

  1. epoll--IO多路复用

    理解 epoll 过程 #include <stdio.h> #include <stdlib.h> #include <string.h> #include &l ...

  2. insert into select 引起的 "子查询返回的值不止一个。当子查询跟随在**之后,或子查询用作表达式时,这种情况是不允许的"

    目录 1.事故现场 1.1 在使用 Insert into Table2 select * from Table1 将表1的数据插入到表2时,报错如下: 1.2 sql 语句 2.推测 3.解决方案 ...

  3. ASP.NET WebApi+Vue前后端分离之允许启用跨域请求

    前言: 这段时间接手了一个新需求,将一个ASP.NET MVC项目改成前后端分离项目.前端使用Vue,后端则是使用ASP.NET WebApi.在搭建完成前后端框架后,进行接口测试时发现了一个前后端分 ...

  4. 深copy

    更好的对一个对象进行复制 using System; using System.Collections.Generic; using System.Linq; using System.Text; u ...

  5. postgresql被注入之后

    本来只是贪便宜买了个一年特价的阿里云服务器,做做测试什么的,结果不知道哪一天开始阿里云安全中心就开始给我发什么安全提示类的信息,一开始我并不在意,因为这些都是套路,不过是想让我升级购买高防盾罢了,反正 ...

  6. Html.CSS.JavaScript 学习经验

    HTML里面 不要使用 document.getElementsByName() 来获取 元素,会出错. 使用 document.getElementById()更好一些. substring()首字 ...

  7. day07整理(内置方法\循环判断)

    目录 一.上节课回顾 (一)if判断 1.单分支结构 2.双分支结构 3.多分支结构 (二)for循环 1.for + break 2.for + continue 3.for循环嵌套 (三)robu ...

  8. Redis(一)Redis基础

    一.Redis是什么 Redis是一种基于键值对(key-value)的NoSQL数据库,与很多键值对数据库不同的是,Redis中的值可以是由string(字符串).hash(哈希).list(列表) ...

  9. 数据结构(三十三)最小生成树(Prim、Kruskal)

    一.最小生成树的定义 一个连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边. 在一个网的所有生成树中,权值总和最小的生成树称为最小代价生成树(Minimum ...

  10. PHP比较IP大小

    function cmpLoginIP($a, $b) { return bindec(decbin(ip2long($a['loginIp']))) > bindec(decbin(ip2lo ...