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即可。
-