[原创]我所理解的Remoting(1):Marshaling & Activation - Part II

在上面一片文章([原创]我所理解的Remoting(1):Marshaling & Activation - Part I ),我花了大量的文字来来描述了Remote Object如何通过Marshaling的过程从Server端所在的Application Domain经过相关的转换(Transformation)传递到Client所在的Application Domain供Client调用; 以及Client的调用请求如何在Activate处于Server端Application Domain的Remote Object。大体的要点如下:

Host在Server端注册Client可能会用到的一到多个Channel用于传输Client发出的调用请求(这个调用请求最终被序列化成一Message)——Channel Registration。然后把Remote Object的相关Metadata信息和remoteObject Uri(Remote Object Type的信息)注册到Host进程中——Object Registration。完成了Object Registration之后,Remoting Framework分析注册的信息Load相应的Assembly,利用Reflection的机制为相应的Remote Type生成一个可序列化ObjRef(可序列化以为着ObjRef对象可以穿梭Application Domain),并将它保存到一个Internal Table 之中(这个Internal Table用于Track Remote Object)。

Remoting有两种Activation 方式——Server Activation 和Client Activation。而Server Activation有具有两种不同的Mode——SingCall和Singleton(SingleCall和Singleton严格地说是关于Instance Management的概念——这个概念在WCF中被引入)。对于Server Activation,Client端根据注册在Client端的Remote Object的Metadata创建Real Proxy和Transparent Proxy。在创建Proxy的时候,不曾有任何访问请求发送到Server端,与此同时,也不可能有相应的Remote Object在Server 端被创建。而真正第一次网络访问发生在第一次通过Transparent Proxy调用某个方法。当这个方法请求从某个注册在Server段的某个Channel抵达Server端的时候,Server 端的RemotingFramework提取请求Message 的Remote Object 的ObjRef,同上面提到的Internal Table的相关Entry进行比较,获得所需的Metadata信息,通过Reflection创建Remote Object。这就是Server Activation的简单过程。

Client Activation采用了不同的Activation 方式——Client端的Proxy(Both Transparent Proxy和Real Proxy )和Remote Object几乎在同时创建(当然在不考虑远程调用时延的因素)。当Client通过New或者Activator.CreateInstance在Client创建Proxy的时候实际上是经历了以下一个过程:一个ActivatorProxy首先在Client端创建,借助这个Activator Proxy Remoting Framework发送一个Activation请求到Server端,Server端的Remoting Framework根据Activation Request的Metadata信息和已经注册的Remote Type做一个匹配,提取所需的Metadata通过Reflection的机制创建Remote Object。同时创建这个Remote Object的ObjRef并通过相应的ChannelForward到Client端,随之生成RealProxy 和Transparent Proxy,Transparent Proxy被Client调用。

上面基本上就是我在上一篇Blog的中心。可能看过我Blog的人都知道,我几乎在每篇文章中都会有一个Sample,我不太相信流于文字的理论,我喜欢用实践来证明。所以下面我们将用Sample来证明。这个Sample中将沿用简单的Calculator的应用。Source Code可以从这里下载(Artech.MyRemoting.zip

1. 整个Solution的结构。

这个结构其实是我比较鄙视的分布式结构——Client端和Server通过Share一个Type System来共享整个Service(包括Interface和Implementation ,在WCF中我们这两部分称为Service Contract和Service Implementation)。但是由于Client Activated Object在创建Proxy的时候需要制定MarshalByRefObject的Type,所以我们不得不用这种结构——Client和Server共享定义在Artech.MyRemoting.RemoteService中定义的MarshalByRefObject Class:CalculatorService。大家可以可以看到Artech.MyRemoting.Hosting和Artech.MyRemoting.Client都有Artech.MyRemoting.RemoteService的Reference。话又说回来,我们可以应用某些策略使只把Service的Interface公开给Client——即使是SAO对象,相关的内容超出了这篇文章范畴,我会相关的讨论放到后续的Remoting相关的Blog中,如有兴趣可以留意。

2. 在Artech.MyRemoting.RemotingService 定义我们的Service——尽管Remoting算不上是完全基于SOA的Distributed Technology,但我还是会不自觉地使用SOA相关的术语,不当的之处,还往见谅。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;

namespace Artech.MyRemoting.RemoteService
ExpandedBlockStart.gifContractedBlock.gif
{
publicclassCalculatorService:MarshalByRefObject
ExpandedSubBlockStart.gifContractedSubBlock.gif
{
privateint_callCount;

publicCalculatorService()
ExpandedSubBlockStart.gifContractedSubBlock.gif
{
Console.WriteLine(
"Remoteobjectisactivatedat{0}\n",DateTime.Now.ToString("hh:mm:ss"));
}


publicdoubleAdd(doublex,doubley)
ExpandedSubBlockStart.gifContractedSubBlock.gif
{
this._callCount++;
returnx+y;
}


publicintGetCallCount()
ExpandedSubBlockStart.gifContractedSubBlock.gif
{
returnthis._callCount;
}

}

}

Code 很简单——一个Constructor用于确定Remote Object到底在什么时候创建或者说的专业一点,真正的Remote Object什么时候被Activated。一个GetCallCount用所Add方法调用次数的计数器,这个计数器用来验证Remoting 的Instance Management。和一个执行加法运算的方法,注意执行一次我们的保存调用次数的变量就是加1。

3. Host CalculatorService

App.Config

<? xmlversion="1.0"encoding="utf-8" ?>
< configuration >
< system .runtime.remoting >
< application name ="Artech.MyRemoting" >
< service >
< wellknown type ="Artech.MyRemoting.RemoteService.CalculatorService,Artech.MyRemoting.RemoteService"
mode
="SingleCall" objectUri ="SingleCall.Calculator.rem" ></ wellknown >
< wellknown type ="Artech.MyRemoting.RemoteService.CalculatorService,Artech.MyRemoting.RemoteService"
mode
="Singleton" objectUri ="Singleton.Calculator.rem" ></ wellknown >
< activated type ="Artech.MyRemoting.RemoteService.CalculatorService,Artech.MyRemoting.RemoteService" ></ activated >
</ service >
< channels >
< channel type ="System.Runtime.Remoting.Channels.Http.HttpChannel,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
port
="1234" ></ channel >
</ channels >
</ application >
</ system.runtime.remoting >
</ configuration >


从这个config文件可以看到,我们为同一个CalculatorService以不同的方式注册了3此——SingleCall,Singleton和CAO。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;

namespace Artech.MyRemoting.Hosting
ExpandedBlockStart.gifContractedBlock.gif
{
classProgram
ExpandedSubBlockStart.gifContractedSubBlock.gif
{
staticvoidMain(string[]args)
ExpandedSubBlockStart.gifContractedSubBlock.gif
{
RemotingConfiguration.Configure(
"Artech.MyRemoting.Hosting.exe.config",false);
Console.WriteLine(
"TheCalculatorserviceshavebeguntolisten");

Console.Read();
}

}

}

很简单,无需赘言。

4. 编写客户端

using System;
using System.Collections.Generic;
using System.Text;
using Artech.MyRemoting.RemoteService;
using System.Runtime.Remoting;
using System.Threading;

namespace Artech.MyRemoting.Client
ExpandedBlockStart.gifContractedBlock.gif
{
classProgram
ExpandedSubBlockStart.gifContractedSubBlock.gif
{
staticvoidMain(string[]args)
ExpandedSubBlockStart.gifContractedSubBlock.gif
{
stringsingelCallAddress="http://localhost:1234/artech.myremoting/singlecall.calculator.rem";
stringsingletonAddress="http://localhost:1234/artech.myremoting/singleton.calculator.rem";
stringcaoAddress="http://localhost:1234/artech.myremoting";

RemotingConfiguration.RegisterActivatedClientType(
typeof(CalculatorService),caoAddress);

Console.WriteLine(
"CreateserverSingleCallproxyat{0}",DateTime.Now.ToString("hh:mm:ss"));
CalculatorServicesingleCallCalculator
=Activator.GetObject(typeof(CalculatorService),singelCallAddress)asCalculatorService;

Thread.Sleep(
10000);
Console.WriteLine(
"CreateserverSingletonproxyat{0}",DateTime.Now.ToString("hh:mm:ss"));
CalculatorServicesingletonCalculator
=Activator.GetObject(typeof(CalculatorService),singletonAddress)asCalculatorService;

Thread.Sleep(
10000);
Console.WriteLine(
"\nCreateclientactivatedobjectproxyat{0}",DateTime.Now.ToString("hh:mm:ss"));
CalculatorServicecaoCalculator
=newCalculatorService();

Thread.Sleep(
10000);
Console.WriteLine(
"\nCallthemethodofSingleCallobjectat{0}",DateTime.Now.ToString("hh:mm:ss"));
InvocateCalculator(singleCallCalculator);

Thread.Sleep(
10000);
Console.WriteLine(
"\nCallthemethodofSingletonobjectat{0}",DateTime.Now.ToString("hh:mm:ss"));
InvocateCalculator(singletonCalculator);

Thread.Sleep(
10000);
Console.WriteLine(
"\nCallthemethodofCAOobjectat{0}",DateTime.Now.ToString("hh:mm:ss"));
InvocateCalculator(caoCalculator);


Console.WriteLine(
"ThetimestoinvovatethecurrentSingleCallremoteobjectis{0}",singleCallCalculator.GetCallCount());
Console.WriteLine(
"ThetimestoinvovatethecurrentSingletonremoteobjectis{0}",singletonCalculator.GetCallCount());
Console.WriteLine(
"ThetimestoinvovatethecurrentCAOremoteobjectis{0}",caoCalculator.GetCallCount());

Console.Read();
}


staticvoidInvocateCalculator(CalculatorServicecalculator)
ExpandedSubBlockStart.gifContractedSubBlock.gif
{
Console.WriteLine(
"x+y={2}wherex={0}andy={1}",1,2,calculator.Add(1,2));
}

}

}


这里有必要多说几句:

我们首先创建基于3种不模式的Proxy,为了弄清楚整个Activation的流程,对于每个操作都为它显示出具体的执行时间,通过操作的执行会间隔一段时间(我给它指定的是10s)

string singelCallAddress = " http://localhost:1234/artech.myremoting/singlecall.calculator.rem " ;
string singletonAddress = " http://localhost:1234/artech.myremoting/singleton.calculator.rem " ;
string caoAddress = " http://localhost:1234/artech.myremoting " ;

RemotingConfiguration.RegisterActivatedClientType(
typeof (CalculatorService),caoAddress);

Console.WriteLine(
" CreateserverSingleCallproxyat{0} " ,DateTime.Now.ToString( " hh:mm:ss " ));
CalculatorServicesingleCallCalculator
= Activator.GetObject( typeof (CalculatorService),singelCallAddress) as CalculatorService;

Thread.Sleep(
10000 );
Console.WriteLine(
" CreateserverSingletonproxyat{0} " ,DateTime.Now.ToString( " hh:mm:ss " ));
CalculatorServicesingletonCalculator
= Activator.GetObject( typeof (CalculatorService),singletonAddress) as CalculatorService;

Thread.Sleep(
10000 );
Console.WriteLine(
" \nCreateclientactivatedobjectproxyat{0} " ,DateTime.Now.ToString( " hh:mm:ss " ));
CalculatorServicecaoCalculator
= new CalculatorService();

依次调用三个Proxy的Add方法显示调用的准确时间

Thread.Sleep( 10000 );
Console.WriteLine(
" \nCallthemethodofSingleCallobjectat{0} " ,DateTime.Now.ToString( " hh:mm:ss " ));
InvocateCalculator(singleCallCalculator);

Thread.Sleep(
10000 );
Console.WriteLine(
" \nCallthemethodofSingletonobjectat{0} " ,DateTime.Now.ToString( " hh:mm:ss " ));
InvocateCalculator(singletonCalculator);

Thread.Sleep(
10000 );
Console.WriteLine(
" \nCallthemethodofCAOobjectat{0} " ,DateTime.Now.ToString( " hh:mm:ss " ));
InvocateCalculator(caoCalculator);

获得他们的计数器,看看调用次数有何不同。

Console.WriteLine( " ThetimestoinvovatethecurrentSingleCallremoteobjectis{0} " ,singleCallCalculator.GetCallCount());
Console.WriteLine(
" ThetimestoinvovatethecurrentSingletonremoteobjectis{0} " ,singletonCalculator.GetCallCount());
Console.WriteLine(
" ThetimestoinvovatethecurrentCAOremoteobjectis{0} " ,caoCalculator.GetCallCount());

现在我们首先启动Hosting,输出表明Server端正常监听。


启动Client,产生如下的输出:


然后我们再看看现在Hosting的输出:


我们现在来分析一下为什么会有如此输出结果:

  • 我们在04:40:02和04:40:12创建了一个SingleCall Proxy,Server端没有反应,这就充分验证了对于Server Activation来说,在Client端创建Proxy的时候,并没有Remote Object在Server端被Activated。
  • 接着我们在04:40:22创建一个CAO Proxy,Remote Object 对象在一分钟后便被Activated。表明Proxy和Remote Object 几乎是同时创建的。
  • 10s后,我们分别调用SingleCall和Singleton Proxy的方法,Server端也在同一时间给出反应,这就说明了,对于Server Activation 来说,第一次调用才会导致Remote Object的Activation。
  • 随后,我们在04:40:53调用CAO Proxy的方法,Server端没有任何输出,因为这个Proxy对应的Remote在Proxy创建的时候就已经被创建了。(Server端的最后一行输出实际上是调用SingleCall Proxy的GetCallCount方法时输出的——对于SingleCall来说,对于Proxy的每次调用都会创建一个Remote Object,调用完毕被Garbage Collected。看来这个Sample 还是不够好,不过相信大家能够理解了)。
  • 接下来,我们分别获取3个对象的调用计数 。对于SingleCalll Proxy 来说,每次调用都会创建一个新的Remote Object,所以Add方法的调用次数永远为零,而对于Singleton来说,所有的Client共享一个Remote Object, 所以它能保持上次来自任意一个Client调用时的State,对于CAO来说,一个Client和一个Remote Object,所以他能够保持自己的调用的State。所以我们不然想象,当我们在开启一个Client,会有什么样的输出:


注: 以上的输出都应该基于这样的前提:创建的Remote Object没有被回收。相关的原理相对比较复杂,它将会出现在的后续的关于Remote Object Lifetime Management的Blog中,有兴趣的网友可以关注。

相关内容:
[原创]我所理解的Remoting(1):Marshaling & Activation - Part I
[原创]我所理解的Remoting(1):Marshaling & Activation - Part II
[原创]我所理解的Remoting(2):远程对象生命周期的管理—Part I
[原创]我所理解的Remoting (2) :远程对象的生命周期管理-Part II
[原创]我所理解的Remoting(3):创建CAO Service Factory使接口和实现相互分离
[原创].NET Remoting: 如何通过Remoting实现双向通信(Bidirectional Communication)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本微信小程序医院挂号预约系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此微信小程序医院挂号预约系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。微信小程序医院挂号预约系统有管理员,用户两个角色。管理员功能有个人中心,用户管理,医生信息管理,医院信息管理,科室信息管理,预约信息管理,预约取消管理,留言板,系统管理。微信小程序用户可以注册登录,查看医院信息,查看医生信息,查看公告资讯,在科室信息里面进行预约,也可以取消预约。微信小程序医院挂号预约系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值