如何用.net Remoting实现一个客户端需要连接多个服务器端?
2010-02-09 15:17
761 查看
比如我们有下面的需求:
三台电脑:A,B,C。
我们在 B 和 C 上部署了同样的一个服务,电脑 A 需要根据客户端的选择,自动的切换到底是调用B的服务,还是C的服务。
要实现这个需求,核心就在客户端的调用上。下面我们用一个简单的演示这个功能的代码来说明如何实现。
首先:服务器段
服务器段逻辑,这是非常简单的,我们按照之前的.net编写规范,编写代码即可。熟悉.net Remoting 的完全可以跳过这部分。
下面是一段简单的服务器段逻辑代码
using System;using System.Collections.Generic;using System.Text;using System.Net;namespace MyServiceComponent{ public class MyComponent : MarshalByRefObject { public string GetString(short s) { // 返回信息中包含服务器IP,这样我们就知道客户端调用的是哪个服务器 if (s <= 10) return string.Format("<=10 {0}", GetIP()); else return string.Format("大于10 {0}", GetIP()); } protected string GetIP() //获取本地IP { IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName()); IPAddress ipAddr = ipHost.AddressList[0]; return ipAddr.ToString(); } }}服务器段的配置
xml version="1.0" encoding="utf-8" ?><configuration> <system.runtime.remoting> <application> <service> <wellknown mode="Singleton" type="MyServiceComponent.MyComponent, MyServiceComponent" objectUri="HongjunguoRemotingService" /> service> <channels> <channel ref="tcp" port="8088" secure="true" impersonate="true" protectionLevel="EncryptAndSign" /> <serverProviders> <formatter href="binary" typeFilterLevel="Full"/> serverProviders> channels> application> <customErrors mode ="Off" /> system.runtime.remoting>configuration>服务器段调用代码RemotingConfiguration.Configure( AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, false); 客户端客户端如果我们用以前常用的,把所有客户端的调用信息都写在一个配置文件中,期望简单的用下面代码就不可以了。 RemotingConfiguration.Configure(configFile, true);如果我们用上面的方法时,则会收到下面的异常:远程处理配置失败,异常为“System.Runtime.Remoting.RemotingException: 试图重定向类型“MyServiceComponent.MyComponent, MyServiceComponent”的激活,而该类型已被重定向。 在 System.Runtime.Remoting.RemotingConfigHandler.RemotingConfigInfo.AddWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfigHandler.RegisterWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfigHandler.RemotingConfigInfo.StoreRemoteAppEntries(RemotingXmlConfigFileData configData) 在 System.Runtime.Remoting.RemotingConfigHandler.ConfigureRemoting(RemotingXmlConfigFileData configData, Boolean ensureSecurity)”。 参考我在论坛咨询的帖子远程处理配置失败,异常为“RemotingException: 试图重定向类型“MySC.MyComponent, MyServiceComponent”的激活,而该类型已被重定向 http://topic.csdn.net/u/20080418/10/a9b02fa0-a230-4fb6-abeb-b7407a6729c1.html 使用.net Remoting 客户端调用服务器段时,需要考虑两个东西:1、信道的问题(Channel)2、如何创建远程对象,也就是注册类型 先说信道的问题:上面例子中, B 和 C 服务器,他们完全可能一个开放的是 TCP 信道,一个开放的是 HTTP 信道。 同时,访问他们服务时,身份验证完全可能是不同的。各自服务器自身的验证。这就有一个需要解决的问题,如何实现客户端多信道。下面这篇博客对此有比较详细的介绍:Remoting多个信道(Chennel)的注册问题/article/5699542.html 创建远程对象的问题:如果我们把需要创建的信息写在配置文件中,用 RemotingConfiguration.Configure(configFile, true); 来创建远程对象,就会出现下面的错误。 远程处理配置失败,异常为“System.Runtime.Remoting.RemotingException: 试图重定向类型“MyServiceComponent.MyComponent, MyServiceComponent”的激活,而该类型已被重定向。 在 System.Runtime.Remoting.RemotingConfigHandler.RemotingConfigInfo.AddWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfigHandler.RegisterWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfigHandler.RemotingConfigInfo.StoreRemoteAppEntries(RemotingXmlConfigFileData configData) 在 System.Runtime.Remoting.RemotingConfigHandler.ConfigureRemoting (RemotingXmlConfigFileData configData, Boolean ensureSecurity)”。 解决方法,就是下面的演示代码,不写在配置文件中,改自己手工创建,如下面客户端演示代码。编码创建对象可以使用 Activator.GetObject 或者 Activator.CreateInstance 。下面就是我的演示代码针对B服务器的配置文件(主要是通道的配置,注意这两个配置文件验证信息不一样)注意,这个配置文件中我们可没有下面这样的信息: displayName ="Wellknown1" type="MyServiceComponent.MyComponent,MyServiceComponent" url="tcp://192.168.5.2:8088/HongjunguoRemotingService" /> s1.configxml version="1.0" encoding="utf-8" ?><configuration> <system.runtime.remoting> <application> <channels> <channel name="Channel1" ref="tcp" port="8081" secure="true" tokenImpersonationLevel="impersonation" protectionLevel="EncryptAndSign" username="ghj1976" password="*****" domain="*****" /> <clientProviders> <formatter ref="binary" typeFilterLevel="Full" /> clientProviders> channels> application> <customErrors mode ="Off" /> system.runtime.remoting>configuration> 针对C服务器的配置文件(主要是通道的配置,注意这两个配置文件验证信息不一样)s2.configxml version="1.0" encoding="utf-8" ?><configuration> <system.runtime.remoting> <application> <channels> <channel name="Channel2" ref="tcp" port="8082" secure="true" tokenImpersonationLevel="impersonation" protectionLevel="EncryptAndSign" username="communityserver" password="****" domain="***"/> <clientProviders> <formatter ref="binary" typeFilterLevel="Full" /> clientProviders> channels> application> <customErrors mode ="Off" /> system.runtime.remoting>configuration> 客户端程序的调用代码 public partial class ClientForm : Form { public ClientForm() { InitializeComponent(); } private Dictionary<string, MyServiceComponent.MyComponent> dict = new Dictionary<string, MyServiceComponent.MyComponent>(2); private void button1_Click(object sender, EventArgs e) { short ss = 0; if (!short.TryParse(this.textBox1.Text, out ss)) return; string key = string.Empty; string url = string.Empty; if (radioButton1.Checked) { key = "s1.config"; url = "tcp://192.168.5.2:8088/HongjunguoRemotingService"; } else if (radioButton2.Checked) { key = "s2.config"; url = "tcp://192.168.5.7:8088/HongjunguoRemotingService"; } else return; MyServiceComponent.MyComponent com = null; if (!dict.TryGetValue(key, out com)) { string configFile = Path.Combine( Path.GetDirectoryName(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile), key); RemotingConfiguration.Configure(configFile, true); //com = new MyServiceComponent.MyComponent(); com = (MyServiceComponent.MyComponent)Activator.GetObject( typeof(MyServiceComponent.MyComponent), url); dict.Add(key, com); } else { if (com == null) return; } string www = com.GetString(ss); MessageBox.Show(www); } } 参考资料 客户端提示 信道 http 已注册http://topic.csdn.net/t/20051219/15/4468126.html如何取消RemotingConfiguration.RegisterActivatedClientType的注册类型http://topic.csdn.net/t/20050116/16/3729762.html RemotingConfiguration.Configure (String, Boolean) 中隐藏的秘密http://blog.csdn.net/blue_sky_blue_heart/archive/2006/08/28/1130914.aspxRemoting给远程对象属性赋值http://topic.csdn.net/u/20070614/15/1d5a7738-e676-489e-978a-b194579d560b.html
三台电脑:A,B,C。
我们在 B 和 C 上部署了同样的一个服务,电脑 A 需要根据客户端的选择,自动的切换到底是调用B的服务,还是C的服务。
要实现这个需求,核心就在客户端的调用上。下面我们用一个简单的演示这个功能的代码来说明如何实现。
首先:服务器段
服务器段逻辑,这是非常简单的,我们按照之前的.net编写规范,编写代码即可。熟悉.net Remoting 的完全可以跳过这部分。
下面是一段简单的服务器段逻辑代码
using System;using System.Collections.Generic;using System.Text;using System.Net;namespace MyServiceComponent{ public class MyComponent : MarshalByRefObject { public string GetString(short s) { // 返回信息中包含服务器IP,这样我们就知道客户端调用的是哪个服务器 if (s <= 10) return string.Format("<=10 {0}", GetIP()); else return string.Format("大于10 {0}", GetIP()); } protected string GetIP() //获取本地IP { IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName()); IPAddress ipAddr = ipHost.AddressList[0]; return ipAddr.ToString(); } }}服务器段的配置
xml version="1.0" encoding="utf-8" ?><configuration> <system.runtime.remoting> <application> <service> <wellknown mode="Singleton" type="MyServiceComponent.MyComponent, MyServiceComponent" objectUri="HongjunguoRemotingService" /> service> <channels> <channel ref="tcp" port="8088" secure="true" impersonate="true" protectionLevel="EncryptAndSign" /> <serverProviders> <formatter href="binary" typeFilterLevel="Full"/> serverProviders> channels> application> <customErrors mode ="Off" /> system.runtime.remoting>configuration>服务器段调用代码RemotingConfiguration.Configure( AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, false); 客户端客户端如果我们用以前常用的,把所有客户端的调用信息都写在一个配置文件中,期望简单的用下面代码就不可以了。 RemotingConfiguration.Configure(configFile, true);如果我们用上面的方法时,则会收到下面的异常:远程处理配置失败,异常为“System.Runtime.Remoting.RemotingException: 试图重定向类型“MyServiceComponent.MyComponent, MyServiceComponent”的激活,而该类型已被重定向。 在 System.Runtime.Remoting.RemotingConfigHandler.RemotingConfigInfo.AddWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfigHandler.RegisterWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfigHandler.RemotingConfigInfo.StoreRemoteAppEntries(RemotingXmlConfigFileData configData) 在 System.Runtime.Remoting.RemotingConfigHandler.ConfigureRemoting(RemotingXmlConfigFileData configData, Boolean ensureSecurity)”。 参考我在论坛咨询的帖子远程处理配置失败,异常为“RemotingException: 试图重定向类型“MySC.MyComponent, MyServiceComponent”的激活,而该类型已被重定向 http://topic.csdn.net/u/20080418/10/a9b02fa0-a230-4fb6-abeb-b7407a6729c1.html 使用.net Remoting 客户端调用服务器段时,需要考虑两个东西:1、信道的问题(Channel)2、如何创建远程对象,也就是注册类型 先说信道的问题:上面例子中, B 和 C 服务器,他们完全可能一个开放的是 TCP 信道,一个开放的是 HTTP 信道。 同时,访问他们服务时,身份验证完全可能是不同的。各自服务器自身的验证。这就有一个需要解决的问题,如何实现客户端多信道。下面这篇博客对此有比较详细的介绍:Remoting多个信道(Chennel)的注册问题/article/5699542.html 创建远程对象的问题:如果我们把需要创建的信息写在配置文件中,用 RemotingConfiguration.Configure(configFile, true); 来创建远程对象,就会出现下面的错误。 远程处理配置失败,异常为“System.Runtime.Remoting.RemotingException: 试图重定向类型“MyServiceComponent.MyComponent, MyServiceComponent”的激活,而该类型已被重定向。 在 System.Runtime.Remoting.RemotingConfigHandler.RemotingConfigInfo.AddWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfigHandler.RegisterWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownClientType(WellKnownClientTypeEntry entry) 在 System.Runtime.Remoting.RemotingConfigHandler.RemotingConfigInfo.StoreRemoteAppEntries(RemotingXmlConfigFileData configData) 在 System.Runtime.Remoting.RemotingConfigHandler.ConfigureRemoting (RemotingXmlConfigFileData configData, Boolean ensureSecurity)”。 解决方法,就是下面的演示代码,不写在配置文件中,改自己手工创建,如下面客户端演示代码。编码创建对象可以使用 Activator.GetObject 或者 Activator.CreateInstance 。下面就是我的演示代码针对B服务器的配置文件(主要是通道的配置,注意这两个配置文件验证信息不一样)注意,这个配置文件中我们可没有下面这样的信息: displayName ="Wellknown1" type="MyServiceComponent.MyComponent,MyServiceComponent" url="tcp://192.168.5.2:8088/HongjunguoRemotingService" /> s1.configxml version="1.0" encoding="utf-8" ?><configuration> <system.runtime.remoting> <application> <channels> <channel name="Channel1" ref="tcp" port="8081" secure="true" tokenImpersonationLevel="impersonation" protectionLevel="EncryptAndSign" username="ghj1976" password="*****" domain="*****" /> <clientProviders> <formatter ref="binary" typeFilterLevel="Full" /> clientProviders> channels> application> <customErrors mode ="Off" /> system.runtime.remoting>configuration> 针对C服务器的配置文件(主要是通道的配置,注意这两个配置文件验证信息不一样)s2.configxml version="1.0" encoding="utf-8" ?><configuration> <system.runtime.remoting> <application> <channels> <channel name="Channel2" ref="tcp" port="8082" secure="true" tokenImpersonationLevel="impersonation" protectionLevel="EncryptAndSign" username="communityserver" password="****" domain="***"/> <clientProviders> <formatter ref="binary" typeFilterLevel="Full" /> clientProviders> channels> application> <customErrors mode ="Off" /> system.runtime.remoting>configuration> 客户端程序的调用代码 public partial class ClientForm : Form { public ClientForm() { InitializeComponent(); } private Dictionary<string, MyServiceComponent.MyComponent> dict = new Dictionary<string, MyServiceComponent.MyComponent>(2); private void button1_Click(object sender, EventArgs e) { short ss = 0; if (!short.TryParse(this.textBox1.Text, out ss)) return; string key = string.Empty; string url = string.Empty; if (radioButton1.Checked) { key = "s1.config"; url = "tcp://192.168.5.2:8088/HongjunguoRemotingService"; } else if (radioButton2.Checked) { key = "s2.config"; url = "tcp://192.168.5.7:8088/HongjunguoRemotingService"; } else return; MyServiceComponent.MyComponent com = null; if (!dict.TryGetValue(key, out com)) { string configFile = Path.Combine( Path.GetDirectoryName(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile), key); RemotingConfiguration.Configure(configFile, true); //com = new MyServiceComponent.MyComponent(); com = (MyServiceComponent.MyComponent)Activator.GetObject( typeof(MyServiceComponent.MyComponent), url); dict.Add(key, com); } else { if (com == null) return; } string www = com.GetString(ss); MessageBox.Show(www); } } 参考资料 客户端提示 信道 http 已注册http://topic.csdn.net/t/20051219/15/4468126.html如何取消RemotingConfiguration.RegisterActivatedClientType的注册类型http://topic.csdn.net/t/20050116/16/3729762.html RemotingConfiguration.Configure (String, Boolean) 中隐藏的秘密http://blog.csdn.net/blue_sky_blue_heart/archive/2006/08/28/1130914.aspxRemoting给远程对象属性赋值http://topic.csdn.net/u/20070614/15/1d5a7738-e676-489e-978a-b194579d560b.html
相关文章推荐
- 如何用.net Remoting实现一个客户端需要连接多个服务器端?
- 如何实现 客户端仅用一个IP地址,就可以连接到不同的服务器上
- android端和pc端使用usb进行socket通信,其中android是服务器端,pc是客户端。如何实现安卓端输入的数据通过按钮发送到pc端?
- 如何实现一个简单的Android推送模块-Socket连接
- 一个XMPP客户端需要实现的基本的XEP
- php如何实现服务器端和客户端的交互
- java在线聊天项目0.7版 连接多个客户端问题,开启多个客户端后服务器端只接收到一个 对各种异常的补充处理
- 利用C语言实现在客户端和服务器端发送一个整数
- VC写的socket程序实现一个简单Echo服务器端和客户端程序
- 多个客户端与一个服务器端通信的问题
- 一个Buton控件如何先执行客户端代码后执行服务器端代码的应用!
- Mina长连接框架实现Android客户端与服务器端通信
- 使用TCP协议编写一个网络程序,设置服务器端的监听端口是8002,当与客户端建立连接后,服务器端向客户端发送数据“Hello, world”,客户端收到数据后打印输出。
- db2的编目(建立一个客户端到服务器端的连接)
- HTML一个form表单中有两个(多个)submit,后台如何区分(纯HTML实现,无需javascript)
- Android网络编程之一个Android下菜单系统模块的实现(开桌功能))(Android客户端+服务器端Servlet+Mysql)
- mysql如何处理一个客户端的连接
- 如何解决客户端与服务器端的连接(mysql) :xxx.xxx.xxx.xxx is not allowed to connect to this mysql serv
- JAVA SOCKET网络编程,服务端接收多个客户端连接的实现
- 如何用LEADTOOLS 实现一个简单的STORE SCU存储客户端