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客戶對象發起。

可以把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不足了,底層代碼會開闢一塊更大的空間,然後重新調用處理函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章