RMI调用流程

RMI

和INetworkModule一样,IRMIModule也是一种进程间通信的机制。而且RMI制定了传输协议,它使用一个字符串常量绑定到一个回调函数,并通过序列化的数据进行数据传输。


RMI组成

一个RMI模型的成分可以是:

  • 常驻内存的RMI服务类型,继承自RMIObject

  • 临时的RMI客户类型,继承自RMIProxyObject

  • 绑定到一个RMI请求的返回类型,继承自RMIBackObject,它属于客户类型的成分

我们必须自己实现这些类型的派生类型。在项目中,服务类型和客户类型大都已经创建完毕,你只需要修改里面的方法即可。比如,一个从loginserver到dataaccess之间的RMI模型为:

  • 服务类型:RMILoginObject

  • 客户类型:RMILoginClient

项目中只有dataaccess提供RMI服务,其余进程若要和dataaccess通信,必须使用RMI。

RMI调用的流程

当dataaccess启动RMI服务后,客户端(这里的客户端是指loginserver、gameworld等服务端进程)就可以创建RMI会话(rmi::Session)了。必须保存该会话,以后将通过会话来发送RMI请求。这一个步骤不需要我们操心,因为都已经写好了。

当我们需要发起一个RMI请求时,就要创建一个RMI客户对象,然后绑定到RMI会话,并创建一个RMI返回对象,它将获得返回的数据。RMI请求由RMI客户对象发起。

扫描二维码关注公众号,回复: 3031268 查看本文章

可以把RMI类比成一个普通的函数调用,RMI服务对象就是被调函数,RMI客户对象就是主调函数,RMI返回对象就是函数的返回值,只不过这个它是一种序列化数据,因此更为复杂。函数的参数也是一种序列化数据。

我们通过这样一个函数发起RMI请求:

/*
    RMI调用
    @session        对该session调用RMI
    @module         远端模块名
    @method         远端方法名
    @in_stream      远端调用的输入参数
    @backobj        返回时的调用对象,注意:该对象由RMI模块在返回调用后调用Free销毁
    @remotec_syn    远端是否阻塞调用
    @return         是否成功提交call请求
*/
bool IRMIModule::Call(const rmi::Session &session, 
    const char *module, const char *method, 
    const TLVSerializer &in_stream, rmi::RMIBackObject *backobj, 
    bool remotec_syn=true, unsigned long timeout=10000)=0;

由于会话绑定了IRMIModule,因此有能力调用Call。大家需要结合实际案例去理解,尤其是RMI调用的流程,一定要搞清楚。

RMI处理函数

RMI处理函数由RMI服务类型定义,它有着固定的类型:


int (*)(TLVUnserializer &in_param, TLVSerializer *out_param);

由于有着固定的定义,所以这些函数可以存放到一张函数表中。表的索引就是上述Call函数的method参数。in_param就是上述Call函数的in_stream,而out_param将传递给backobj作为返回数据。

Note

TLVSerializer和TLVUnserializer是可以互相转换的,因为它们本质上是一个buffer。如果你细心的话,会发现in_param和in_stream类型不一致,但实际上其真实的数据是一致的。

函数的返回类型定义在枚举:ERMIDispatchStatus,它的定义如:

enum ERMIDispatchStatus
{
    DispatchOK,
    DispatchObjectNotExist,
    DispatchMethodNotExist,
    DispatchParamError,
    DispatchOutParamBuffTooShort,
    SessionDisconnect,
};

如果调用成功,我们需要返回DispatchOK。如果反序列化失败,通常返回DispatchParamError,如果序列化失败(Push),通常调用DispatchOutParamBuffTooShort。其余返回值由底层代码处理。

关于DispatchOutParamBuffTooShort

项目中你看到有些情况返回了DispatchOutParamBuffTooShort,并打印了一条Critical日志,看上去很吓人。我认为这应当是一种编程失误(可能有极个别情况的确是Critical),这是由于没有理解前人这样写,后人又只会照着抄的缘故。那么,这个返回值意味着什么呢?意味着序列化所需要的buffer不足了,底层代码会开辟一块更大的空间,然后重新调用处理函数。

猜你喜欢

转载自blog.csdn.net/jonWei/article/details/82319296
今日推荐