5.8 Provider间数据交换


  • 5.8.4 客户端开发

    所有类型客户端均支持隧道数据转发。


    • C++/C#/Java 客户端,以Java版本为例

      实现limax.endpoint.EndpointListener的同时,并列实现limax.endpoint.TunnelSupport接口。


      public interface TunnelSupport {
          void onTunnel(int providerid, int label, Octets data) throws Exception;
          void registerTunnelSender(TunnelSender sender);
      }
      
      public interface TunnelSender {
          void send(int providerid, int label, Octets data)
                  throws InstantiationException, SizePolicyException, CodecException, ClassCastException;
      }
      

      实现onTunnel,即可收到服务器发送过来的隧道数据。Limax框架决定了,一个Endpoint可以同时连接多个Provider,这里的providerid进行了区分。onTunnel可以实现为即时转发,也可以暂存数据(暂存时长不可超过配置的有效期),以后转发。

      Endpoint初始化时,将回调registerTunnelSender,必须实现registerTunnelSender将当前Endpoint的tunnelSender保存下来,之后在该tunnelSender上转发隧道数据。

      通常情况下,客户端需要使用两个Endpoint,EA,EB分别连接隧道两边的Provider,EA.onTunnel收到隧道数据时,通过EB.tunnelSender转发。

      这里必须当心,TunnelSupport.onTunnel中的providerid是源Provider的id, TunnelSender.send中的providerid是目的Provider的id,不能像label,data一样直接转发。

      不支持TunnelSupport的Endpoint,忽略接收到的隧道数据。


    • 脚本客户端,以Javascript版本为例

      脚本客户端在创建Limax实例时,将一个函数作为第三个参数传入,即可支持隧道数据接收。


      var limax = Limax(function(ctx) {
      ctx.onerror = function(e) {
          print('limax error', e);
      }
      ctx.onclose = function(e) {
          print('limax close', e);
      }
      ctx.onopen = function() {
          .........................
      }
      }, cache, function(pvid, label, data) {
      });
      

      limax实例本身就是一个函数,直接执行 limax(pvid, label, data); 即可发送隧道数据。


    • 使用了ScriptEngineHandle的混合客户端(Java/javscript,C#/javascript,C#/Lua,C++/javascript,C++/Lua,各种形式的极简模式客户端),以Java/javascript为例

      使用带有TunnelReceiver参数的构造函数创建相应的ScriptHandle,即可实现隧道数据的接收。


      new JavascriptHandle(new ScriptEngineManager().getEngineByName("javascript"),
          new InputStreamReader(Main.class.getResourceAsStream("example.js")), 
          null, 
          null,
          new TunnelReceiver() {
              @Override
              public void onTunnel(int providerid, int label, String data) {
                  System.out.println(providerid + " " + label + " " + data);
              }
      });
      

      这里的data来自脚本系统所以类型为String,实际上,这是Octets类型隧道数据的Base64编码结果。

      注意观察ScriptEngineHandle接口的定义


      public interface ScriptEngineHandle {
          .......................
          void tunnel(int providerid, int label, String data) throws Exception;
          void tunnel(int providerid, int label, Octets data) throws Exception;
      }
      

      ScriptEngineHandle上直接调用tunnel方法即可发送隧道数据。来自于脚本系统的隧道数据使用带有String参数的方法发送,来自TunnelSupport的隧道数据使用带有Octets参数的方法发送。

      注意:

      1. 如果客户端的EndpointListener实现了TunnelSupport接口,又使用了支持TunnelReceiver的ScriptEngineHandle,同一份隧道数据,两处都能接收到。

      2. 如果客户端的EndpointListener实现TunnelSupport时记录了TunnelSender,又使用了ScriptEngineHandle,两处都可以用来发送隧道数据。


  • 5.8.5 运行管理

    • 配置文件

      Provider配置文件中,Provider节点内,需要添加一个Tunnel节点。


      <Provider ...>
          <Tunnel compressor="ZIP" keyProtector="HMACSHA256" defaultExpire="86400000" defaultGroup="prjA">
              <PKIX location="pkcs12:/work/keyalloc.p12" passphrase="123456" revocationCheckerOptions="SOFT_FAIL"/>
              <SharedKey group="prjA" key="123456" /> 
              <SharedKey group="prjB" key="123456" /> 
              <Expire group="prjA" value="3600"/>
          </Tunnel>
          <Manager .../>
          <Manager .../>
          ...
      <'/Provider>
      

      Tunnel节点4个属性

      compressor:源数据压缩方法,可选值NONE,RFC2118,ZIP,默认为NONE。参见附录《外部数据》

      keyProtector:源数据保护算法,可选值HMACSHA224,HMACSHA256,HMACSHA384,HMACSHA512,TripleDESCBC,AESCBC128,默认为HMACSHA256。参见附录《外部数据》

      defaultExpire:隧道数据默认过期时间,单位毫秒,默认3600000。过期时间的配置必须小于key寿命,参见附录《Key分发系统》

      defaultGroup:默认信任域。

      Tunnel节点下支持2种节点,PKIX与SharedKey,PKIX节点具有高优先级,配置了PKIX节点SharedKey节点被忽略。


      配置了多个PKIX节点,第一个节点有效,PKIX节点配置了Key分发系统客户端,请求Key分发网络分配Key保护隧道数据。


      PKIX节点5个属性。

      location:provider证书包的location。

      passphrase:location的私钥启用密码,实际运营时,不应该填写该属性,而应该在服务器启动时输入。

      trustsPath:信任证书路径, location中已经包含了派生该证书的ROOTCA, 如果要信任其它ROOTCA(或者当前ROOTCA即将过期,应该将新的ROOTCA放置在这里), 则需要配置trustsPath, trustsPath可以是一个文件, 也可以是一个目录, 如果是目录, 遍历一层, 获取文件, 文件允许任何证书格式, 包括CER, DER, PKCS7, PKCS12, KeyStore, 从中获取ROOTCA,忽略所有错误。

      revocationCheckerOptions:服务器检测对方证书回收状态的选项,可选的值为DISABLE, NO_FALLBACK, ONLY_END_ENTITY, PREFER_CRLS, SOFT_FAIL, 大小写不敏感,后4个参数的解释见java.security.cert.PKIXRevocationChecker.Option,DISABLE具有最高优先级,如果配置了DISABLE,其它配置无意义。

      httpsHost:指定key分发网络中特定的入口服务器IP或者域名,不配置该属性,使用provider证书中提供的域名。

      PKIX节点配置初始化之后,从Provider证书中提取支持的信任域集合校验defaultGroup配置,如果配置了defaultGroup,defaultGroup必须在集合中存在,否则抛出运行时异常;如果没有配置defaultGroup,在集合中挑选一个作为defaultGroup。


      不存在PKIX节点的情况下,使用SharedKey节点的配置,SharedKey节点允许多个,静态配置了信任域和相应的key。SharedKey配置方式不使用Key分发系统,用于调试环境,或者极其简单的应用场景。


      SharedKey节点2个属性

      group:信任域名称

      key:信任域key

      所有SharedKey配置初始化之后,生成了静态的信任域集合,如果配置了defaultGroup,defaultGroup必须在集合中存在,否则抛出运行时异常;如果没有配置defaultGroup,在集合中挑选一个作为defaultGroup。


      Expire节点2个属性

      group:信任域名称

      value:过期时间

      Expire节点允许精细配置特定信任域的隧道数据过期时间。


    • 运行时注意事项

      1. 运行ntp服务,同步provider时钟

      2. 配置正确的dns服务。

      3. 按照CA的要求,配置trustsPath,添加CA提供的额外ROOTCA。

      4. 开启防火墙,许可443目的端口,确保与CAServer,Key分发网络的连通性。


  • 5.8.6 高级话题

    • 应用数据组织

      1. Provider间数据交换框架不考虑具体的应用数据,专注于转发Octets

      2. 信任域内Provider,应该设计私有的可交换数据结构,使用xml描述生成交换用的公共bean是理想方式。

      3. 如果存在多种公共bean,应该设计类型字段予以区分,简单的情况下,可以考虑利用label区分类型。

      4. 使用JSON表示用户数据也是一种可行的选择,JSON串上可以统一使用UTF8编码getBytes,然后wrap为Octets。

      5. 应用数据尺寸可能较大的情况,配置压缩。


    • 隧道数据尺寸

      1. 隧道数据通过特定协议发送。

      2. 出于服务器的抗攻击考虑, 虚拟机参数limax.net.Engine.limitProtocolSize, 限制了最大协议大小1M, 隧道数据尺寸不可超出这一约束, 否则, 目的服务器解析协议时将出错。

      3. 客户端信任服务器,所以客户端不控制数据尺寸。

      4. 对于大量数据,应该考虑多次发送的方式。


    • 隧道谁的数据

      1. 仔细规划应用自己的协商过程,决定隧道谁的数据。

      2. 多数情况,通过隧道转发用户自己的数据。

      3. 特定情况下,可以通过没有利害冲突的第三方传送。这时,真实的sessionid打包在应用数据中,解码获得该sessionid之后如果需要线程安全地处理,应该使用View.schedule(sessionid, task)将后续任务调度到sessionid对应线程上。

      4. 出于规避防火墙的考虑,可以设计专用客户端,部署在连通性良好的网络中,转发 Provider间数据。


上一页 下一页