.NET Remoting 自行切换通道

Posted

技术标签:

【中文标题】.NET Remoting 自行切换通道【英文标题】:.NET Remoting switching channels by itself 【发布时间】:2011-02-18 14:45:39 【问题描述】:

.NET Remoting 有一个奇怪的问题。基本上,我们有一个用ChannelServices.RegisterChannel()注册两个TcpChannel的服务器:

    一个监听端口 50000 另外一个监听15000端口。

然后我们有一个客户端,它注册了一个 TcpChannel 以便能够与服务器通信。我们通过使用 URI 调用 Activator.GetObject() 从服务器检索一个对象

"tcp://serverip:50000/objectname"

这工作正常,客户端连接到端口 50000 上的服务器并获取对象。

但是,当我们开始对该对象调用方法时,与端口 50000 上的通道的连接将被断开,并且会自动与端口 15000 上的通道建立新连接。这对我们来说是一个真正的问题,因为我们不希望端口 15000 上的流量,因为该通道可能未绑定到与服务器上的端口 50000 通道相同的网络适配器,或者该端口可能未在防火墙中打开,这会导致远程调用自然会失败。

这对我们来说很奇怪,因为客户端在我们的代码中不知道服务器上的端口 15000 上存在另一个通道或它侦听的 IP,但它却尝试连接到它。

非常感谢您对此的任何帮助,

谢谢, 卡斯珀

这是设置服务器通道之一的代码,通常在端口 50000 上:

IDictionary props = new Hashtable();

props["port"] = m_tcpPort;
props["name"] = String.Empty;


BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();

m_tcpChannel = new TcpServerChannel( props, /*clientProvider,*/ serverProvider );
ChannelServices.RegisterChannel( m_tcpChannel, false );

m_wellKnownObjRef = RemotingServices.Marshal( this, "Server@" + m_tcpPort.ToString() );

这是设置另一个服务器通道的代码,通常在端口 15000:

IDictionary props = new Hashtable();

props["name"] = String.Empty;
props["port"] = ip.Port;
props["bindTo"] = ip.Address.ToString();                    
props["timeout"] = REMOTING_TIMEOUT; // Timeout to prevent hung remoting calls.

if (!String.IsNullOrEmpty( machineName ))

    props["machineName"] = machineName;


    BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
    serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

    BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();

    m_channel = new TcpChannel( props, clientProvider, serverProvider );
    ChannelServices.RegisterChannel( m_channel, false );

    m_objRef = RemotingServices.Marshal( this, QueueName ); // Queuename is a GUID.

这是连接到第一个服务器通道的客户端中的代码,通常在端口 50000 上:

IDictionary props = new Hashtable();

props["port"] = 0;

RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off;

BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();

m_tcpChannel = new TcpClientChannel(props, clientProvider/*, serverProvider*/);
ChannelServices.RegisterChannel(m_tcpChannel, false );

string address = "tcp://" + profile.RemoteIP + ":" + profile.RemoteTCP;

m_server = (Kernel)Activator.GetObject(typeof(Server), address + "/Server@" + port);

【问题讨论】:

如果您在 app.config 文件中有任何频道配置,请将其添加到您的问题中。 感谢您的回答。没有 app.config 配置,因为它都是在代码中设置的。我现在已将该代码添加到问题中。 【参考方案1】:

我们已向 Microsoft 记录了一个关于此问题的支持案例,显然,.NET Remoting 不支持我们在此执行的操作。您只能在一个 AppDomain 中注册每种类型的一个频道。 Remoting 所做的是将对象的 URI 发送回客户端,告诉客户端它可以在哪里访问相关对象。当它这样做时,它会在服务器端查看已注册的通道,并使用它在那里找到的与请求的类型匹配的第一个通道(在我们的例子中:Tcp)。换句话说,它将使用碰巧首先注册的任何通道。它根本不关心客户端连接的通道。

解决方案是在客户端实现自己的 IClientChannelSinkProvider。当您实现 CreateSink() 方法时,您可以选择在创建要使用的接收器时希望客户端连接到的 url。

【讨论】:

感谢您的解释!我们一直在寻找为什么我们的服务器在为多个 NIC 创建通道时并不总是正确响应的原因。原因和解决方法如你所述。【参考方案2】:

我也确实与那些“反向链接”端口作斗争;我认为只有在服务器想要发回某些东西时才会发生这种情况(即使是在事件过程中)。 因为我一直遇到防火墙问题,所以我切换到 GenuineChannels(虽然我认为这有点过时)。

【讨论】:

远程处理本身现在已经过时,被 WCF 取代。 确实如此。我们遇到问题的代码是在 .NET Framework 1.0 刚刚发布时写回的。这些年来似乎没有人注意到这个问题,直到我们的一位客户尝试将这两个通道绑定到不同的网络适配器。

以上是关于.NET Remoting 自行切换通道的主要内容,如果未能解决你的问题,请参考以下文章

C# Remoting的一个简单例子

.net remoting 实现通用消息处理窗口

Remoting自定义通道

asp。net 中的B/S项目中Remoting的应用?ASP.NET B/S项目中能做成有的状态?

.NET2.0 Remoting - 为啥需要注册 ClientChannel?

.Net Remoting,防火墙问题