• 分布式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 FilesZeroCIce-3.7.4in文件夹,我们可以看到有名为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技术汇

  • 相关阅读:
    使用truffle测试部署合约
    nodejs promise深度解析
    pthread线程特定数据
    基于信号量与互斥锁实现的生产者和消费者
    Linux coredump 的打开和关闭
    Linux 双网卡配置两个IP同时只有一个会通的原因
    进程间通信-共享内存
    进程间通信-消息队列
    TCP/IP SIGPIPE信号
    Select模式和超时
  • 原文地址:https://www.cnblogs.com/dereklovecc/p/13466628.html
Copyright © 2020-2023  润新知