1 / 83

Remoting

Remoting. 杨圣洪 hbxxysh2@sohu.com. 为什么要学习 Remoting. 想 在 WEB 服务中直接调用 EXE 组件程序,如Word与Excel , csc test.cs 。均无法实现,所以试着: 1) 把 exe 放到 webService 目录下,允许写权限。 在文件夹上添加了 aspnet 所有权限。 2)IIS 使用 windows 身份验证 , 客户端加 NetworkCredential, 使用 administrator 账户 . 3) 在服务中,将“ ASP.NET 状态服务”登录设置“允许与桌面交互”。

baker-nolan
Télécharger la présentation

Remoting

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Remoting 杨圣洪 hbxxysh2@sohu.com

  2. 为什么要学习Remoting 想在WEB服务中直接调用EXE组件程序,如Word与Excel, csc test.cs。均无法实现,所以试着: 1)把exe放到webService目录下,允许写权限。 在文件夹上添加了aspnet所有权限。 2)IIS使用windows身份验证, 客户端加NetworkCredential,使用administrator账户. 3)在服务中,将“ASP.NET 状态服务”登录设置“允许与桌面交互”。 4) 设置“服务”中“IIS Admin”之“登录”,勾选“服务与桌面交互”,重启IIS 5)在web.config里面模拟里管理员帐户。 <identity impersonate="true" userName="xx\Administrator" password="***" />

  3. 为什么要学习Remoting 1)建虚拟目录wsRemote1 2)建Web服务http://localhost/wsRemote1 3)添加如下WebMethod: [WebMethod] public void RemotCompile(string srcFileName){ System.Diagnostics.ProcessStartInfo info=new ProcessStartInfo(); info.FileName = "cmd.exe"; info.UseShellExecute =false; info.RedirectStandardInput =true; info.RedirectStandardOutput =true; info.RedirectStandardError = true; info.CreateNoWindow = true; string cmdStr = "regedit"; //"csc "+srcFileName; System.Diagnostics.Process proc=System.Diagnostics.Process.Start(info); proc.StandardInput.WriteLine(cmdStr); proc.StandardInput.WriteLine("exit"); }

  4. 为什么要学习Remoting 键入http://localhost/wsremote1/service1.asmx,看不到

  5. 为什么要学习Remoting 键入http://localhost/wsremote1/service1.asmx,看不到 在“服务”中将将“ASP.NET 状态服务”登录设置“允许与桌面交互”,不起作用! 在“服务”中将将“IIS Admin”登录设置“允许与桌面交互”,不起作用! 所以只好寻求新方法,想到曾成功配置过DCOM,故选用新版DCOM,即.NET平台中的Remoting。 WEB服务是互联网上调用服务的技术,利用.NET Remoting技术,可调用服务器中的方法。

  6. 为什么要学习Remoting Remoting技术使用任何类型应用程序定义域中的服务,包括了主控台应用程序、Windows Form、Internet Information Services (IIS)、XML Web Service 或 Windows 服务。 采用二进制格式通讯。 以传址方式(By Reference)传递对象,并传回特定应用程序定义域中的特定对象。 必须直接控制启动过程、对象的生命期。 可定制信道或通讯协议,满足特定需求。 直接参与通讯处理,以建立所需的功能。 建立更复杂的应用程序类型

  7. Remoting基本概念 一、对象类型 1、单次调用对象(Single Call object) 调用一次后被释放,无状态。 2、单一对象(singleton object)单个实例 多客户端共1个服务端,有状态,COM组件类似 可节省服务器的内存资源等,提高响应速度 3、客户端激活(client-activated object) 客户端调用方法时才激活,这与COM的激活方式一样,随着激活客户端的死亡而消失,如果激活者一直在线又不使用服务端对象,这时造成资源浪费,因此有各种生存期控制方式。 COM组件是综合了(2)(3)二种激活方式。

  8. Remoting基本概念 二、托管程序Managed 用C++编写了.net的执行环境CLR,即C:\WINDOWS\Microsoft.NET\Framework中的各种程序, 用.net编写的程序都在该环境中运行, 该环境提供了托管堆、垃圾回收、JIT编译等服务。 用非.net编写的程序称为非托管程序,它与托管程序之间可以互相调用,但要进行相应的设置。 三、应用程序域AppDomain 不同的应用程序运行在不同程序域中。 但不同应用程序可以共同一个程序域中。 每个正在执行的程序默认有一个程序域。

  9. Remoting基本概念 三、应用程序域AppDomain 1)获取当前程序所属域 AppDomain currentDomain = AppDomain.CurrentDomain; AppDomain currentDomain = Thread.GetDomain(); 2)获取当前程序所属域的名称 string name = AppDomain.CurrentDomain.FriendlyName; 3)创建新域 AppDomain newDomain = AppDomain.CreateDomain("NewD"); 4)在应用程序域中创建对象 DemoClass obj = (DemoClass)AppDomain.CurrentDomain.CreateInstanceAndUnWrap("ClassLib", "ClassLib.DemoClass");//dll文件名 名字空间.类名 ObjectHandle obj2= AppDomain.CurrentDomain.CreateInstance("ClassLib", "ClassLib.DemoClass");DemoClass obj = (DemoClass)obj2.UnWrap();

  10. 应用程序域实例 1、建立类库项目ClassLib2 using System; namespace ClassLib2{ public class DemoClass { private int count=0; public DemoClass(){ Console.WriteLine("DemoClass的对象已创建");} public void ShowCount() { count++; Console.WriteLine("count={0},所在域为={1}",this.count, AppDomain.CurrentDomain.FriendlyName);} public void ShowAppDomain() { AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine("服务端所在程序域={0}",cd.FriendlyName); } }}

  11. 应用程序域实例 2、建立控制台ClassLib2ClientA并引用ClassLib2 using System; //添加引用 using ClassLib2; namespace ClassLib2ClientA{ class Class1 { [STAThread] static void Main(string[] args) { AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine("客户端程序域={0}",cd.FriendlyName); ClassLib2.DemoClass obj=(DemoClass)cd.CreateInstanceAndUnwrap( "ClassLib2","ClassLib2.DemoClass"); Console.WriteLine("构造函数被执行吗?"); obj.ShowAppDomain();//该方法是在ClassLib2的域中 obj.ShowCount(); //还是在ClassLib2ClientA的域中执行 Console.ReadLine();}}}

  12. 应用程序域实例 3、执行ClassLib2ClientA,可看到效果为: ClassLib2.dll它所在程序域,与ClassLib2ClientA.exe所在一样,说明DLL与调用方在同一个进程中。 如果在ClassLib2ClientA.exe中新建程序域,再调用ClassLib2.dll中的方法,会出现“ClassLib2.DemoClass 未标记为可序列化”错!为了试验该错误,而新建控制台ClassLib2ClientB.exe

  13. 应用程序域实例 4、建立控制台ClassLib2ClientB并引用ClassLib2 using System; using ClassLib2; namespace ClassLib2ClientB{ class Class1 { [STAThread] static void Main(string[] args) { AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine("客户端程序域={0}",cd.FriendlyName); AppDomain nd=AppDomain.CreateDomain("新域"); DemoClass obj=nd.CreateInstanceAndUnwrap("ClassLib2", "ClassLib2.DemoClass") as DemoClass; obj.ShowAppDomain(); obj.ShowCount(); Console.ReadLine();} }} 运行时肯定出错,为此新建ClassLib3.dll实现Serializable

  14. 应用程序域实例 5、建立类库项目ClassLib3 using System; namespace ClassLib3{ [Serializable] public class DemoClass { private int count=0; public DemoClass(){ Console.WriteLine("类DemoClass的构造函数被执行"); AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine("构造函数中的服务端所在程序域={0}",cd.FriendlyName); } public void ShowCount(){ count++; Console.WriteLine("count={0}",this.count);} public void ShowAppDomain() { AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine("执行服务端函数时所在程序域={0}",cd.FriendlyName); }}}

  15. 应用程序域实例 6、建立控制台ClassLib3ClientA并引用ClassLib3 using System; using ClassLib3; namespace ClassLib3ClientA{ class Class1 { [STAThread] static void Main(string[] args){ AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine("客户端程序域={0}",cd.FriendlyName); AppDomain nd=AppDomain.CreateDomain("新域"); DemoClass obj=nd.CreateInstanceAndUnwrap("ClassLib3", "ClassLib3.DemoClass") as DemoClass; obj.ShowAppDomain(); obj.ShowCount(); Console.ReadLine();} }} //这时能在“新域”中,正常调用ClassLib3.dll。

  16. 应用程序域实例 7、执行ClassLib3ClientA,可看到效果为: ClassLib3.dll之类DemoClass的实例在新域被构造。 其方法却运行于客户端ClassLib3ClientA.exe所在域中 说明 “序列化”起作用了, 已将DemoClass的实例,整体传送到客户方域中。 ClassLib2ClientA.exe与ClassLib2.dll同域 ClassLib2ClientB.exe与ClassLib2.dll不同域 ClassLib3ClientA.exe与ClassLib3.dll不同域,但已序列化

  17. 代理proxy与封送Marshalling 8、代码中 方式一DemoClass obj=new DemoClass(); 方式二DemoClass obj= nd.CreateInstanceAndUnwrap("ClassLib3", "ClassLib3.DemoClass") as DemoClass; 方式一是在CLR即执行环境的“托管堆”中创建对象,犹如在本地创建对象一样。 方式二创建2个对象,一个在"新域"中,一个在客户方所在程序域ClassLib3ClientA.exe中。 在“新域”中创建对象后,对该对象进行序列化、封送到ClassLib3ClientA.exe域中,再解封并反序列化, 在客户方重新构建该对象,相当于进程迁移

  18. 代理proxy与封送Marshalling 8、 在“新域”中创建对象后,对该对象进行序列化、并且封送,送到ClassLib3ClientA.exe域中,再解封并反序列化,在客户方重新构建该对象 。付出代价 以上那种在本地重构远程对象的方式,称为传值封送(Marshal by Value),采用方法CreateInstanceAndUnwrap重构远程对象的方法很少使用,传值封送仅用来传递数值等标量数据对象,代价很高! 一般在客户方只创建远程对象的本地代理,这时需要远程对象的元数据metadata即接口信息,不需要远程对象的实现代码,这与COM组件是一样的。 对于客户方而言,本地代理就是远程对象。 好比长沙海尔服务部,就代表海尔公司。

  19. 代理proxy与封送Marshalling 一般在客户方只创建远程对象的本地代理,这时需要远程对象的元数据metadata即接口信息,不需要远程对象的实现代码,这与COM组件是一样的。 这时需要对远程对象类的定义进行修改 去掉ClassLib3.dll中的[Serializable], 修改其基类为MarshalByRefObject 如果有[Serializable]则在客户程序域中,重建被调用的对象! 为此新建类库文件ClassLib4,其代码如下:

  20. 代理proxy与封送Marshalling 9、新建类库文件ClassLib4.dll,其代码如下: using System; namespace ClassLib4{ public class DemoClass:System.MarshalByRefObject { private int count=0; public DemoClass() { AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine("类DemoClass的对象构造之域:"+ cd.FriendlyName);} public void ShowCount() { count++; Console.WriteLine("count={0}",this.count);} public void ShowAppDomain(){ AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine("调用服务端程序域={0}",cd.FriendlyName); } }}

  21. 代理proxy与封送Marshalling 10、新建ClassLib4.dll的客户端ClassLib4ClientA,: using System; using ClassLib4;//添加引用ClassLib4 namespace ClassLib4ClientA{ class Class1 { [STAThread] static void Main(string[] args){ AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine("客户端程序域={0}",cd.FriendlyName); AppDomain nd=AppDomain.CreateDomain("新域"); DemoClass obj=nd.CreateInstanceAndUnwrap("ClassLib4", "ClassLib4.DemoClass") as DemoClass;//新域创建对象 obj.ShowAppDomain();//调用远程对象的方法 obj.ShowCount(); Console.ReadLine();} }}

  22. 应用程序域实例 11、执行ClassLib4ClientA,可看到效果为: 构造远程对象,调用远程对象的方法均在“新域”, 与ClassLib3ClientA.exe不一样, ClassLib3.dll中 “序列化”,整体传送到客户方域中MBV ClassLib4.dll中未序列化,仅在客户方建立远程对象的代理Marshal By Reference,对象仍在远程域中执行。

  23. Remoting的体系结构 12、前面学习远程对象的类型、程序域的概念、跨程序域就是远程调用。方法有: 传送有传值封送MBV(远程对象要Serializable)、 传引用封送MBR(远程对象派生于MarshalByRefObject) Remoting技术是一种跨域调用技术,它采用MBR调用远程对象,本地创建远程对象代理,方法执行仍在远程域中,其基本组成为: (1)派生于MarshalByRefObject远程对象,保存在类库文件中。 (2)远程对象的执行环境或宿主程序,可为多种形式。 需要用到Channel、Formatter、StackBuilder. (3)客户方可为多种形式。 需要用到proxy、 Channel 、Formatter。

  24. 远程服务组件(程序集) 12、 建立类库文件ClassLib5 using System; namespace ClassLib5{ public class DemoClass:MarshalByRefObject { //MBR方式发送引用到客户端 private int count = 0; public DemoClass() { AppDomain cd = AppDomain.CurrentDomain; Console.WriteLine(" 远程对象构造时:"+cd.FriendlyName);} public void ShowCount(){ count++;Console.WriteLine("类中count={0}.", count);} public void ShowAppDomain(){ AppDomain cd = AppDomain.CurrentDomain; Console.WriteLine("执行远程对象的域="+cd.FriendlyName);} public int GetCount() { return count;}}}

  25. 远程服务程序集的执行环境 13、ClassLib5.dll执行环境ClassLib5Srv.exe(dosapp) 执行“添加引用”选择ClassLib5.dll,还选择如下dll(版本) C:WINDOWS\Microsoft.NET\Frameworkv\1.4322\System.Runtime.Remoting.dll using System;//只有此句是向导生成 using ClassLib5; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Remoting.Channels.Http; namespace ClassLib5Srv{ class Class1{ [STAThread] static void Main(string[] args) {….} }}

  26. 远程服务程序集的执行环境 13、ClassLib5.dll执行环境ClassLib5Srv.exe(dosapp) namespace ClassLib5Srv{ class Class1{ [STAThread] static void Main(string[] args) { IChannelReceiver tcpChn1=new TcpChannel(8601);//tcp ChannelServices.RegisterChannel(tcpChn1); //注册通道 IChannel httpChn1=new HttpChannel(8602);//http ChannelServices.RegisterChannel(httpChn1); RemotingConfiguration.ApplicationName="Remote1"; Type t=typeof(ClassLib5.DemoClass); //注册服务类,客户方激活方式,可自定义构造函数,有状态 RemotingConfiguration.RegisterActivatedServiceType(t); Console.WriteLine("远程对象就绪");Console.Read(); }}} //客户方呼叫指定服务器的指定通道

  27. 远程服务程序集的客户端 14、ClassLib5.dll客户端ClassLib5Clt.exe(dosapp) 执行“添加引用”选择ClassLib5.dll,尽管选择了此dll,只是用来建立本地代理,还要选择如下dll(注意版本) C:WINDOWS\Microsoft.NET\Frameworkv\1.4322\System.Runtime.Remoting.dll using System; using ClassLib5; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Remoting.Channels.Http; namespace ClassLib5Clt{ class Class1 { [STAThread] static void Main(string[] args){ …}}}

  28. 远程服务程序集的客户端 14、ClassLib5.dll客户端ClassLib5Clt.exe(dosapp) namespace ClassLib5Clt{ class Class1 { [STAThread] static void Main(string[] args) { //IP:端口/程序域,类名 Type t=typeof(ClassLib5.DemoClass); //远程对象类 string url=@"tcp://127.0.0.1:8601/Remote1"; //客户方激活方式,客户端new本地代理时,服务也构造对象 RemotingConfiguration.RegisterActivatedClientType(t,url); ClassLib5.DemoClass obj=new DemoClass();//本地代理 Console.WriteLine("本地代理已创建");Console.Read(); obj.ShowAppDomain(); //执行结果显示在服务器中 obj.ShowCount(); Console.WriteLine("远程返回的count="+ obj.GetCount().ToString());Console.ReadLine();}}}

  29. 远程程序的调用过程 15、执行ClassLib5Srv.exe 再执行ClassLib5Clt.exe,可看到效果为:

  30. 远程对象的激话方式 通过ClassLib5Srv.exe与ClassLib5Clt.exe的执行可知, 当客户方建立远程对象的本地代理时,远程对象的构造函数被调用即远程对象被创建,与COM稍有不同,执行远程方法时才创建远程对象。 每创建本地代理,就创建一个远程对象,非单实例! 这种方式,称为客户方激话。 服务方注册对象方法: Type t=typeof(ClassLib5.DemoClass);//远程对象类 RemotingConfiguration.RegisterActivatedServiceType(t); 客户方调用对象的方法: Type t=typeof(ClassLib5.DemoClass);//远程对象类 string url=@"tcp://127.0.0.1:8601/Remote1";//位置RemotingConfiguration.RegisterActivatedClientType(t,url);

  31. 远程对象的激话方式 17、服务方激话-SingleCall(仅被单次调用) 客户方每调用一次服务方法,自动创建一个实例。 1、新建服务方执行环境ClassLib5SrvSingleCall.exe 添加对ClassLib5.dll的引用 添加对System.Runtime.Remoting.dll的引用 using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Remoting.Channels.Http; 2、新建客户方ClassLib5CltSingleCall.exe 添加对ClassLib5.dll的引用 添加对System.Runtime.Remoting.dll的引用 using语句同执行环境。

  32. 远程服务程序集的执行环境 17、ClassLib5.dll宿主程序ClassLib5SrvSingleCall namespace ClassLib5SrvSingleCall{ class Class1 { [STAThread] static void Main(string[] args) { IChannelReceiver tcpChn1=new TcpChannel(8601); ChannelServices.RegisterChannel(tcpChn1); IChannel httpChn1=new HttpChannel(8602); ChannelServices.RegisterChannel(httpChn1); Type t=typeof(ClassLib5.DemoClass);//DC为类的别名 RemotingConfiguration.RegisterWellKnownServiceType( t,"DC",WellKnownObjectMode.SingleCall); RemotingConfiguration.ApplicationName="Remote2"; Console.WriteLine("远程对象的执行环境等待访问...."); Console.Read(); }}}

  33. 远程服务程序集的客户端 17、ClassLib5CltSingleCall.exe namespace ClassLib5CltSingleCall{ class Class1 { [STAThread] static void Main(string[] args) { Type t=typeof(ClassLib5.DemoClass); string url=@"tcp://127.0.0.1:8601/Remote2/DC"; RemotingConfiguration.RegisterWellKnownClientType(t,url); ClassLib5.DemoClass obj=new DemoClass();//创建地代 Console.WriteLine("客户方创建了本地对象"); //服务没反应 Console.ReadLine(); obj.ShowAppDomain(); obj.ShowCount(); Console.WriteLine("远程返回值"+ obj.GetCount().ToString()); Console.ReadLine(); }}}

  34. 远程程序的调用过程 17、执行ClassLib5SrvSingleCall.exe, 再执行ClassLib5CltSingleCall.exe, 客户方创建对象时,远程对象的构造函数未执行 每执行1个方法就执行1次构造函数,即构造出1对象

  35. 远程对象的激话方式 17、服务方激话-Singleton: 当客户方创建本地代理对象时,远程服务方的构造函数不调用,即远程对象不创建。 当有客户首次调用远程对象的函数时,远程对象被构造一次,节约资源!!! 服务方注册对象方法: RemotingConfiguration.ApplicationName="Remote2"; Type t=typeof(ClassLib5.DemoClass);//远程对象类 RemotingConfiguration.RegisterWellKnownServiceType( t,"DC",WellKnownObjectMode.Singleton); 客户方调用对象的方法: Type t=typeof(ClassLib5.DemoClass); string url=@"tcp://127.0.0.1:8601/Remote2/DC"; RemotingConfiguration.RegisterWellKnownClientType(t,url);

  36. 远程服务程序集的执行环境 18、ClassLib5.dll执行环境ClassLib5SrvSingleton namespace ClassLib5SrvSingleton{ //单实例 class Class1 { [STAThread] static void Main(string[] args) { IChannelReceiver tcpChn1=new TcpChannel(8601); ChannelServices.RegisterChannel(tcpChn1); IChannel httpChn1=new HttpChannel(8602); ChannelServices.RegisterChannel(httpChn1); Type t=typeof(ClassLib5.DemoClass); //注册对象 RemotingConfiguration.RegisterWellKnownServiceType( t,"DC",WellKnownObjectMode.Singleton); //仅此句不同 RemotingConfiguration.ApplicationName="Remote2"; Console.WriteLine("远程对象的执行环境等待访问...."); Console.Read(); }}}

  37. 远程服务程序集的客户端 18、ClassLib5CltSingleton.exe namespace ClassLib5CltSingleton { class Class1 { [STAThread] static void Main(string[] args) { Type t=typeof(ClassLib5.DemoClass); //类名即接口信息 string url=@"tcp://127.0.0.1:8601/Remote2/DC"; RemotingConfiguration.RegisterWellKnownClientType(t,url); ClassLib5.DemoClass obj=new DemoClass(); //t绑于url Console.WriteLine("客户方创建了本地对象"); Console.ReadLine(); obj.ShowAppDomain(); obj.ShowCount(); Console.WriteLine("远程返回值"+ obj.GetCount().ToString()); Console.ReadLine(); }}} //客户方运行多次后,服务方只有1个,Count显示被调用数

  38. 远程程序的调用过程 18、执行ClassLib5SrvSingleton.exe, 再执行ClassLib5CltSingleton.exe, 客户方创建对象时,远程对象的构造函数未执行 多个客户端只执行1个构造函数,即只有1个实例!共享也

  39. 远程对象的激话方式 18、服务方激话方式-SingleCall: 当客户方创建对象(new DemoClass()),远程服务方的构造函数不调用,即远程对象未创建。 每调用远程对象的函数一次,远程对象构造一次。 服务方注册对象方法: RemotingConfiguration.ApplicationName="Remote2"; Type t=typeof(ClassLib5.DemoClass);//远程对象类 RemotingConfiguration.RegisterWellKnownServiceType( t,"DC",WellKnownObjectMode.SingleCall); 客户方调用对象的方法-不变! Type t=typeof(ClassLib5.DemoClass); string url=@"tcp://127.0.0.1:8601/Remote2/DC"; RemotingConfiguration.RegisterWellKnownClientType(t,url);

  40. 自定义通道 19、前面各例的通道是采用TCP或HTTP,消息的格式是采用默认格式。服务方多个端口其实只要一个即可 如果通道是TCP,则消息格式为Binary二进制 如果通道是HTTP,则消息格式为SOAP。 可重新定义通道与消息格式 public TcpChannel(IDictionary properties, IClientChannelSinkProvider clientSinkProvider, IServerChannelSinkProvider serverSinkProvider); IDictionary是key,已经预先定义好了的 属性/值 集合,属性有通道名称、端口号等。 IClientChannelSinkProvider:客户端通道消息所采用的格式; IServerChannelSinkProvider:服务端通道消息所采用的格式 创建服务端消息格式clientSinkProvider=null, 创建客户端消息格式serverSinkProvider=null,

  41. 远程服务程序集的执行环境 19、ClassLib5.dll执行环境ClassLib5SrvSelfChannel 添加ClassLib5.dll,System.Runtime.Remoting.dll using System; using ClassLib5; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; using System.Runtime.Remoting.Channels.Tcp; using System.Collections;//自定义通道必须新引用此类 namespace ClassLib5SrvSelfChannel{ class Class1 { [STAThread] static void Main(string[] args){ …… } }}

  42. 远程服务程序集的执行环境 19、ClassLib5.dll执行环境ClassLib5SrvSelfChannel static void Main(string[] args){ IServerChannelSinkProvider formatter;//消息格式Binary formatter = new BinaryServerFormatterSinkProvider(); IDictionary propertyDic = new Hashtable(); propertyDic["name"] = "CustomTcp";//默认Tcp,现自定义 propertyDic["port"] = 8601;//端口号, 引用时仍是tcp!! IChannel tcpChnl = new TcpChannel( propertyDic, null, formatter);//客户端消息格式为null ChannelServices.RegisterChannel(tcpChnl); Type t=typeof(ClassLib5.DemoClass);//注册对象 RemotingConfiguration.RegisterWellKnownServiceType( t,"DC",WellKnownObjectMode.Singleton); RemotingConfiguration.ApplicationName="Remote2"; Console.WriteLine("远程执行环境");Console.Read();}

  43. 远程服务程序集的客户端 19、ClassLib5CltSelfChannel.exe //using同执行环境 namespace ClassLib5CltSingleCall{ class Class1 { [STAThread] static void Main(string[] args) { Type t=typeof(ClassLib5.DemoClass); string url=@"tcp://127.0.0.1:8601/Remote2/DC"; RemotingConfiguration.RegisterWellKnownClientType(t,url); ClassLib5.DemoClass obj=new DemoClass(); Console.WriteLine("客户创建对象"); Console.ReadLine(); obj.ShowAppDomain(); obj.ShowCount(); Console.WriteLine("远程返回值"+ obj.GetCount().ToString()); Console.ReadLine();}}}

  44. 客户端不注册直接创建对象 20、前面各例的客户端,采用如下语句注册远程对象 Type t=typeof(ClassLib5.DemoClass);//远程对象类 string url=@"tcp://127.0.0.1:8601/Remote1";//位置 RemotingConfiguration.RegisterActivatedClientType(t,url); 或 string url=@"tcp://127.0.0.1:8601/Remote2/DC"; RemotingConfiguration.RegisterWellKnownClientType(t,url); 然后使用如下语句构造远程对象的本地代理: ClassLib5.DemoClass obj=new DemoClass(); 能否不注册直接构造远程对象呢?可以! 但只能服务激活对象,且创建的对象只能有无参数的构造函数,并且在获得对象的同时创建代理。很少使用! RemotingServices.Connect(t,url) as DemoClass、 Activator.GetObject(t,url) as DemoClass、 Activator.CreateInstance(t,null,new UrlAttribute(url)) as

  45. 下载远程对象到客户端(一) 21、前面各例中,为了提高系统的运行效率,远程对象都在服务端的执行环境即宿主程序域中执行,仅通过传引用封送(Marshal By Reference)在客户端建立代理。 有时出于某种需求,希望远程对象的方法或函数在客户端执行,如待处理的文件在客户端,这时需要传值封送(Marshal By Value). 软件按次使用按次付费!云计算不就是这种模式吗? 为此建立ClassLib6.dll,它包含ClassLib5.dll中类DemoClass,还新建类ExeClass,新类中执行一个EXE文件,完成对cs源程序的编译。 新建ClassLib6Srv.exe与ClassLib6Client.exe, 对ClassLib6.dll与System.Runtime.Remoting.dll添加引用。

  46. 远程服务程序集 21、新建ClassLib6.dll,添加DemoClass、ExeClass using System; namespace ClassLib6{ public class DemoClass:MarshalByRefObject { public DemoClass() { Console.WriteLine(" 类DemoClass的对象已建立"); } public void ShowAppDomain() { AppDomain cd = AppDomain.CurrentDomain; Console.WriteLine("DemoClass的对象所在域="+ cd.FriendlyName);} public ExeClass getExeClass(){ return new ExeClass();} }}

  47. 远程服务程序集 21、新建ClassLib6.dll,添加DemoClass、ExeClass using System; using System.Diagnostics;//因为要执行DOS命令 namespace ClassLib6{ [Serializable] public class ExeClass{ public ExeClass(){ Console.WriteLine("类ExeClass的对象已创建");} public bool CompileCSharp(string srcFileName){ bool isOk=true; try{ //…… } catch { isOk=false; } return isOk;}}} //每个类的一个cs文件

  48. 远程服务程序集 21、新建ClassLib6.dll,添加DemoClass、ExeClass public bool CompileCSharp(string srcFileName){ bool isOk=true; try{ ProcessStartInfo info=new ProcessStartInfo(); info.FileName = "cmd.exe"; info.UseShellExecute =false; info.RedirectStandardInput =true; info.RedirectStandardOutput =true; info.RedirectStandardError = true; info.CreateNoWindow = true; string cmdStr = "csc "+srcFileName; Process proc=Process.Start(info); proc.StandardInput.WriteLine(cmdStr); proc.StandardInput.WriteLine("exit"); AppDomain cd=AppDomain.CurrentDomain; Console.WriteLine(" 类ExeClass域:"+cd.FriendlyName);} catch {isOk=false; } return isOk; }}}

  49. 远程服务程序集的执行环境 21)ClassLib6.dll执行环境ClassLib6Srv.exe (using略) namespace ClassLib6Srv{ class Class1{ [STAThread] static void Main(string[] args) { IChannelReceiver tcpChn1=new TcpChannel(8601); ChannelServices.RegisterChannel(tcpChn1);//通道 Type t=typeof(ClassLib6.DemoClass); RemotingConfiguration.RegisterWellKnownServiceType( t,"DC",WellKnownObjectMode.Singleton);//类名 //定义程序域名 RemotingConfiguration.ApplicationName="Remote2"; Console.WriteLine("远程执行环境已启动...."); Console.Read(); }}}

  50. 远程服务程序集的客户端 21)ClassLib6.dll的ClassLib6Client.exe (using略) namespace ClassLib6Client{ class Class1{ //将源程序临时下发客户端内存或磁盘 [STAThread] //编译完后将其源程序删除 static void Main(string[] args){ //注册对象-- 协议://IP:port/程序域/对象名 Type t=typeof(ClassLib6.DemoClass); string url=@"tcp://127.0.0.1:8601/Remote2/DC"; RemotingConfiguration.RegisterWellKnownClientType(t,url); ClassLib6.DemoClass obj=new DemoClass(); obj.ShowAppDomain();//传引送封送对象的域在服务端 ClassLib6.ExeClass obj2=obj.getExeClass(); bool isOk=obj2.CompileCSharp("test.cs");//编译在客户端 Console.WriteLine(" 编译结果:"+isOk.ToString()); }}} //因为不可能将所有类库安装在客户端。

More Related