如何用.net Remoting实现一个客户端需要连接多个服务器端?

比如我们有下面的需求:

三台电脑: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)的注册问题
http://www.cnblogs.com/kriss/archive/2005/11/30/288177.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.config


  
  xml 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.config


  
  xml 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.aspx

Remoting给远程对象属性赋值
http://topic.csdn.net/u/20070614/15/1d5a7738-e676-489e-978a-b194579d560b.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
.NET Standard 中使用 Remoting 需要使用 System.Runtime.Remoting 命名空间下的类。以下是使用 Remoting 的基本步骤: 1. 创建一个 Remoting 服务端应用程序,并在其中定义一个远程对象。使用 System.Runtime.Remoting.RemotingConfiguration.Configure() 方法来启用 Remoting 支持。 2. 在客户端应用程序中,使用 System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownClientType() 方法来注册远程对象的类型,并使用 Activator.GetObject() 方法来获取远程对象的实例。 3. 通过远程对象的代理,客户端可以调用远程对象的方法。 以下是一个简单的示例代码: 服务端应用程序: ```csharp using System; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; namespace RemotingServer { class Program { static void Main(string[] args) { TcpServerChannel channel = new TcpServerChannel(8080); ChannelServices.RegisterChannel(channel, false); RemotingConfiguration.RegisterWellKnownServiceType( typeof(MyService), "MyService", WellKnownObjectMode.Singleton); Console.WriteLine("Remoting server is running..."); Console.ReadLine(); } } public class MyService : MarshalByRefObject { public string SayHello(string name) { return $"Hello, {name}!"; } } } ``` 客户端应用程序: ```csharp using System; using System.Runtime.Remoting; namespace RemotingClient { class Program { static void Main(string[] args) { RemotingConfiguration.RegisterWellKnownClientType( typeof(MyService), "tcp://localhost:8080/MyService"); MyService service = (MyService)Activator.GetObject( typeof(MyService), "tcp://localhost:8080/MyService"); string result = service.SayHello("World"); Console.WriteLine(result); Console.ReadLine(); } } public class MyService : MarshalByRefObject { public string SayHello(string name) { return $"Hello, {name}!"; } } } ``` 在上面的示例中,服务端应用程序创建了一个名为 MyService 的远程对象,并将其注册为单例模式。客户端应用程序使用 RemotingConfiguration.RegisterWellKnownClientType() 方法注册远程对象类型,并使用 Activator.GetObject() 方法获取远程对象的实例。然后,客户端应用程序通过远程对象的代理调用 MyService.SayHello() 方法,该方法返回一个字符串,表示问候语。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值