.NET Remoting 自行切换通道

发布于 2024-09-01 10:35:41 字数 3009 浏览 3 评论 0原文

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

  1. 一个监听端口 50000,
  2. 另一个监听端口 15000。

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

“tcp://serverip:50000/对象名称”

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

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

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

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

谢谢, Casper

这是设置一个服务器通道的代码,通常在端口 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);

We are having an odd problem with .NET Remoting. Basically, we have a server which registers two TcpChannels with ChannelServices.RegisterChannel():

  1. One listens on port 50000
  2. Other one listens on port 15000.

We then have a client that registers a TcpChannel to be able to communicate with the server. We retrieve a an object from the server by calling Activator.GetObject() with the URI

"tcp://serverip:50000/objectname"

and this works fine, the client connects to the server on port 50000 and gets the object.

However, when we start calling methods on that object, the connection to the channel on port 50000 is dropped, and a new connection is made to the channel on port 15000 automatically. This poses a real problem for us since we don't want traffic on port 15000 because that channel may not be bound to the same network adapter as the port 50000 channel on the server or that port may not be open in the firewall, which causes the remoting calls to fail naturally.

This is very strange to us since the client has no knowledge in our code that there exists another channel on the server on port 15000 or what IP it listens on, yet it attempt to connect to it.

Any help on this is greatly appreciated,

Thanks,
Casper

This is the code that sets up one of the server channels, the one usually on port 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() );

This is the code that sets up the other server channel, usually on port 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.

This is the code in the client that connects to the first server channel, the one that's usually on port 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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橪书 2024-09-08 10:35:42

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

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

We've logged a support case with Microsoft about this and apparently, what we're doing here is not supported by .NET Remoting. You are only allowed to register one channel of each type in one AppDomain. What Remoting does is that it sends back the URI of the object to the client to tell it where it can access the object in question. When it does that it looks through the registered channels at the server end and uses the first channel that it finds there that matches the type requested (in our case: Tcp). In other words it will use whatever channel happens to get registered first. It doesn't care at all about what channel the client has connected on.

The solution is to implement your own IClientChannelSinkProvider on the client side. When you implement the CreateSink() method you can choose what url you want the client to connect to when you create the sink to use.

风筝有风,海豚有海 2024-09-08 10:35:42

我也确实在那些“反向链接”端口上遇到了困难;我认为只有当服务器想要发回某些内容时(即使在事件过程中)才会发生这种情况。
因为我的防火墙总是存在问题,所以我切换到 GenuineChannels(尽管我认为这有点过时)。

I did stuggle with those "backlinked" ports as well; I thought it would only occure if the server wants to send something back (even in an event-procedure).
Because I had always problems with the firewalls, I switched to GenuineChannels (though I think that's a bit outdated).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文