分布式RPC框架ZeroC Ice簡介


開發分布式或較大型的軟件時,必不可少的要進行系統間通信,目前比較常用的框架有Http RestFul,Thrift,gRPC等等,今天分享的ZeroC Ice也是其中一員。

ZeroC公司出品的Ice(Internet Communication Engine)框架專注於RPC通信,經過了10多年的發展,已經非常的成熟,它的主要優點是高性能,跨語言,跨平台,面向對象,開源等等,可以查看其官方網站(https://zeroc.com/products/ice) 了解更多。這里簡單介紹一下它的架構和使用方法。

架構和基本概念

先上一張從ZeroC官方網站上截的圖:

ZeroC Ice Arch

從圖中可以看出,使用Ice的程序分為客戶端和服務器端,而兩端的代碼都由以下三部分組成:

  1. 應用程序代碼,這是由使用者編寫的部分
  2. 自動生成的代碼,由Ice提供的工具自動生成的,為client端生成的叫proxy,為server端生成的叫skeleton
  3. Ice庫代碼,這部分是Ice框架的核心部分,各個平台都有對應的庫

從整體來看,Ice框架的結構還是很清晰的,下面介紹幾個關鍵的概念:

  • Slice(Specification Language for Ice):用於定義client和server通信接口的領域特定語言(DSL),在 https://doc.zeroc.com/ice/3.7/the-slice-language 中有關於它的詳細信息
  • Communicator:Ice運行時的入口點,它所關聯的資源包括:線程池,運行時的配置屬性,對象工廠,Logger(用於處理Ice運行時產生的log消息),Plug-in manager,Object Adapters等
  • Ice Object:是一個抽象的概念,它具有類型,標識等信息,有點像C#或Java里類的概念
  • Servants:上面說到Ice Object是抽象概念,而這里的Servant就是提供具體操作的實體,它負責響應client請求的,一個Servant可以對應一個或者多個Ice Object
  • Proxy:代表Ice Object,client使用proxy來和server交互
  • Ice Object Adapter:存在服務端的communicator中,負責Ice運行時和Server端應用代碼的交互,它會和一個或多個Endpoint綁定並接收client端的請求,然后把請求轉給對應的Servant從而執行應用代碼

使用方法

在了解了Ice的結構和基本概念之后,讓我們動手寫個demo看看具體怎么使用吧。為了體現Ice的跨語言和跨平台功能,我們這里用Java實現server端,用C#實現client端。程序的主要功能:client可以通過向sever發送A股的股票代碼來獲得其對應公司的詳細信息, 下面我們一起看看具體的步驟。(注:這里的公司信息都是dummy的)

  1. 下載並安裝Ice

    https://zeroc.com/download/Ice/3.7/Ice-3.7.4.msi 下載Ice 3.7.4並安裝,筆者把它安裝在了D:\Program Files下面,打開D:\Program FilesZeroC\Ice-3.7.4\bin文件夾,我們可以看到有名為slice2java.exe, slice2cs.exe的程序,這些就是用來自動生成Java和C#代碼的,我們在下面會用到。除了Java和C#的代碼生成器,還有許多其他語言的,如:cpp, php等等
    install dir

  2. 定義client和service的交互接口:這里我們定義兩個class:CompanyInfo和AStockService:

   module com
   {
      module astock
      {
          class CompanyInfo
          {
              int id;
              string name;
              string addr;
          }
      }
  }

  module com
  {
      module astock
      {
          interface AStockService
          {
              CompanyInfo GetCompanyInfo(int id);
          }
      }
  }   
  1. 使用1中的工具把2中定義的類生成C#和Java對應的代碼

    打開cmd,執行下圖中的命令,通過執行slice2java和slice2cs程序,我生成了如下圖所示的代碼,其中C# code只有一個文件,而Java code有四個文件

  2. 生成Code的簡單介紹

    C#雖然只有一個文件,但是里面包含了三個接口,三個類,一個委托,如下圖:

    • AStockServiceOperations_接口:包含了我們定義的操作即GetCompanyInfo
    • AStockService接口:我們定義的接口,它繼承自AStockServiceOperations_
    • AStockServicePrx接口:客戶端代理接口
    • CompanyInfo類: 用於傳遞數據的DTO
    • AStockServiceDisp_類: 服務端的dispatch抽象類,即上文中說到的skeleton,它實現了我們定義的接口AStockService
    • AStockServicePrxHelper: 客戶端的代理類,它實現了AStockServicePrx接口

    Java的code生成了兩個類,兩個接口

    • AStockService接口:我們定義的接口,也是服務端的skeleton
    • AStockServicePrx接口:客戶端代理接口
    • CompanyInfo類: 用於傳遞數據的DTO
    • _AStockServicePrxI類:客戶端代理類
  3. 編寫服務端代碼

    用熟悉的IDE新建一個工程,筆者使用的Intelij Idea,把上面生成的Java代碼加到項目中,並添加Ice的Maven依賴,如下圖所示,當然也可以手動下載ice jar包,並手動添加。

    下面創建一個類AStockServiceServer,實現AStockService接口,其GetCompanyInfo方法返回一個dummy CompanyInfo對象,如下所示

    
     public class AStockServiceServer implements AStockService {
         @Override
         public CompanyInfo GetCompanyInfo(int id, Current current) {
             CompanyInfo info = new CompanyInfo();
             info.id = 1234;
             info.name = "中國平安";
             info.addr = "深圳";
             return info;
         }
     }
    
    

    創建包含main的class AStockServiceServerMain,如下所示:

    public class AStockServiceServerMain {
        public static void main(String[] args) {
            try (Communicator communicator = Util.initialize()) {//創建communicator
            ObjectAdapter oa = communicator.createObjectAdapterWithEndpoints("AStockServiceAdapter", "default -p 10000");//創建一個Adatper,Id是AStockServiceAdapter,綁定到10000端口

            AStockServiceServer servant = new AStockServiceServer();//我們的服務
            oa.add(servant, Util.stringToIdentity("AStockService"));//把我們創建的服務加到上面創建的adapter里
            oa.activate();//激活adapter
            System.out.println("AStock Service Server is running");//輸出啟動log
            communicator.waitForShutdown();//等待結束
        }
    }
}
  1. 編寫客戶端代碼

    用VS新建一個控制台程序,並把上面生成的C#代碼加入項目中,然后添加Ice的nuget包,如下圖所示:

    在main函數中編寫如下代碼:


    class Program
    {
        static void Main(string[] args)
        {
            using (var communicator = Util.initialize(ref args))//創建Communicator對象
            {
                ObjectPrx basePrx = communicator.stringToProxy("AStockService:default -p 10000");//創建客戶端基類代理

                AStockServicePrx aStockServicePrx = AStockServicePrxHelper.checkedCast(basePrx);//把基類代理轉換為子類代理
                var companyInfo = aStockServicePrx.GetCompanyInfo(1000);//調用GetCompanyInfo方法

                Console.WriteLine($"id:{companyInfo.id} name:{companyInfo.name} addr:{companyInfo.addr}");//輸出返回結果
            }
        }
    }

  1. 聯調

先運行Java服務端,然后再啟動C#程序可以得到如下結果,可以看到Client端成功的獲取到了CompanyInfo對象。

總結

本文介紹了ZeroC Ice的概念並用一個demo詳細說明了具體使用方法,完整代碼請參考 https://github.com/DerekLoveCC/Writings/tree/master/Article/zerocIce/code ,期望對讀者能夠有所幫助

Fintech技術匯


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM