5.5 客户端开发


  • 5.5.4 C#客户端

    C#客户端同样支持静态模式,Variant模式和脚本模式。这里介绍静态模式和Variant模式。

    以下代码以VS2013控制台项目举例。

    • 静态模式

      1. 首先应该创建C#解决方案和应用项目,确定应用项目的源码目录sdir,执行如下生成命令:

      2.

      java -jar <path to limax.jar> xmlgen –c# –noServiceXML –outputPath sdir example.client.xml
      

      3. 源码目录里面将看见两个新建目录xmlsrc与xmlgen。xmlgen无需提交到版本控制系统。

      4. 按照生成目录结构,在项目内建立同样的目录结构,然后使用添加现有项操作手工添加所有生成文件,以后的新的生成文件也必须手工添加。

      5. 将C#版本的limax项目添加到解决方案中。

      6. 为应用项目添加引用,引用到limax项目。

      最后形成大致如下的解决方案树结构。


      class Program
      {
          private const int providerId = 100;
          private static void start()
          {
              Endpoint.openEngine();
              EndpointConfig config = Endpoint.createEndpointConfigBuilder(
                      "127.0.0.1", 10000, LoginConfig.plainLogin("testabc", "123456", "test"))
                  .staticViewClasses(example.ExampleClient.share.ViewManager.createInstance(providerId))
                  .build();
              Endpoint.start(config, new MyListener());
          }
          private static void stop()
          {
              object obj = new object();
              Action done = () => { lock (obj) { Monitor.Pulse(obj); } };
              lock (obj)
              {
                  Endpoint.closeEngine(done);
                  Monitor.Wait(obj);
              }
          }
          static void Main(string[] args)
          {
              start();
              Thread.Sleep(2000);
              stop();            
          }
      }
      

      这个主函数代码看起来和java版本无区别。


      class MyListener : EndpointListener
      {
          public MyListener()
          {
          }
          public void onAbort(Transport transport)
          {
              Exception e = transport.getCloseReason();
              Console.WriteLine("onAbort " + transport + " " + e);
          }
          public void onManagerInitialized(Manager manager, Config config)
          {
              Console.WriteLine("onManagerInitialized " + config.GetType().Name + " " + manager);
          }
          public void onManagerUninitialized(Manager manager)
          {
              Console.WriteLine("onManagerUninitialized " + manager);
          }
          public void onTransportAdded(Transport transport)
          {
              Console.WriteLine("onTransportAdded " + transport);
              MySessionView.getInstance().registerListener(e => Console.WriteLine(e));
          }
          public void onTransportRemoved(Transport transport)
          {
              Exception e = transport.getCloseReason();
              Console.WriteLine("onTransportRemoved " + transport + " " + e);
          }
          public void onSocketConnected()
          {
              Console.WriteLine("onSocketConnected");
          }
          public void onKeyExchangeDone()
          {
              Console.WriteLine("onKeyExchangeDone");
          }
          public void onKeepAlived(int ms)
          {
              Console.WriteLine("onKeepAlived " + ms);
          }
          public void onErrorOccured(int source, int code, Exception exception)
          {
              Console.WriteLine("onErrorOccured " + source + " " + code + “ “ + exception);
          }
      }
      

      除了ViewChangedEvent,内部用属性的方法实现访问,其它方面也无区别。

      MyTemporaryView.java内部实现:

      MyTemporaryView.java


      override protected void onOpen(ICollection<long> sessionids) {
          Console.WriteLine(this + " onOpen " + sessionids);
          registerListener(e => Console.WriteLine(e));
          MySessionView.getInstance().control(99999);
      }
      override protected void onClose() { Console.WriteLine(this + " onClose"); }    
      

      编译运行程序,结果:

      onManagerInitialized DefaultEndpointConfig EndpointManagerImpl

      onSocketConnected

      onKeyExchangeDone

      onTransportAdded limax.net.StateTransportImpl

      [class = MyTemporaryView ProviderId = 100 classindex = 2 instanceindex = 6] onOpen System.Collections.Generic.HashSet`1[System.Int64]

      [class = MyTemporaryView ProviderId = 100 classindex = 2 instanceindex = 6] 61440 _var0 Hello 61440 NEW

      [class = MySessionView ProviderId = 100 classindex = 1] 61440 var0 Hello 61440 NEW

      onKeepAlived 47

      [class = MySessionView ProviderId = 100 classindex = 1] 61440 var0 99999 REPLACE

      [class = MyTemporaryView ProviderId = 100 classindex = 2 instanceindex = 6] 61440 _var0 99999 REPLACE

      onTransportRemoved limax.net.StateTransportImpl System.Exception: channel closed manually

      [class = MyTemporaryView ProviderId = 100 classindex = 2 instanceindex = 6] onClose

      onManagerUninitialized EndpointManagerImpl

      跟前面各版本均一致。


    • Variant模式

      修改EndpointConfig的定义为:


      EndpointConfig config = Endpoint.createEndpointConfigBuilder(
              "127.0.0.1", 10000, LoginConfig.plainLogin("testabc", "123456", "test"))
          .variantProviderIds(100)
          .build();    
      

      使用variantProviderIds提供PVID参数。

      修改onTransportAdded为:


      private class MyTemporaryViewHandler : TemporaryViewHandler
      {
          private readonly VariantView mySessionView;
          public MyTemporaryViewHandler(VariantView v) { mySessionView = v; }
          public void onOpen(VariantView view, ICollection<long> sessionids)
          {
              Console.WriteLine(view + " onOpen " + sessionids);
              view.registerListener(e => Console.WriteLine(e));
              Variant param = Variant.createStruct();
              param.setValue("var0", 99999);
              mySessionView.sendControl("control", param);
          }
          public void onClose(VariantView view) { Console.WriteLine(view + " onClose"); }
          public void onAttach(VariantView view, long sessionid) { }
          public void onDetach(VariantView view, long sessionid, int reason) { }
      }
      
      public void onTransportAdded(Transport transport)
      {
          Console.WriteLine("onTransportAdded " + transport);
          VariantManager manager = VariantManager.getInstance((EndpointManager)transport.getManager(), providerId);
          VariantView mySessionView = manager.getSessionOrGlobalView("share.MySessionView");
          mySessionView.registerListener(e => Console.WriteLine(e));
          manager.setTemporaryViewHandler("share.MyTemporaryView", new MyTemporaryViewHandler(mySessionView));
      }    
      

      和Java版本比起来,除了C#不支持通过匿名类直接创建对象,不得不定义MyTemporaryViewHandler外,没有任何区别。

      编译运行程序,结果:

      onManagerInitialized DefaultEndpointConfig EndpointManagerImpl

      onSocketConnected

      onKeyExchangeDone

      onTransportAdded limax.net.StateTransportImpl

      [view = share.MyTemporaryView ProviderId = 100 classindex = 2 instanceindex = 8] onOpen System.Collections.Generic.HashSet`1[System.Int64]

      [view = share.MyTemporaryView ProviderId = 100 classindex = 2 instanceindex = 8] 61440 _var0 Hello 61440 NEW

      [view = share.MySessionView ProviderId = 100 classindex = 1] 61440 var0 Hello 61440 NEW

      onKeepAlived 38

      [view = share.MySessionView ProviderId = 100 classindex = 1] 61440 var0 99999 REPLACE

      [view = share.MyTemporaryView ProviderId = 100 classindex = 2 instanceindex = 8] 61440 _var0 99999 REPLACE

      onTransportRemoved limax.net.StateTransportImpl System.Exception: channel closed manually

      [view = share.MyTemporaryView ProviderId = 100 classindex = 2 instanceindex = 8] onClose

      onManagerUninitialized EndpointManagerImpl

      跟前面各版本均一致。


    • C#版本总结

      C#版本客户端除了少数语言特性带来的差异外,使用方法与注意事项均与Java版本一致。框架提供的类库结构,直接参考javadoc文档即可。

      C#异常规范不够完备,处理各种EndpointListener消息时,建议不要抛出任何异常。

      框架使用了.NET3.5的C#语言特性,由于网络认证过程使用了Diffie-Hellman协议作密钥交换,需要BigInteger支持。如果只能使用.NET3.5,就应该另找一个.NET4.0以上的BigInteger库引用进来。

      另外,limax.util包下提供了两个辅助方法,runOnUiThread与uiThreadSchedule,便于应用在自己的UI线程中调度View消息通告。创建配置的时候 .executor(r => runOnUiThread),然后在自己的UI线程空闲时调用uiThreadSchedule即可。


上一页 下一页