Friday, August 13, 2010

.NET Remoting and Multiple Interfaces/NICs/networks

Have you ever tried to run a .NET remoting application on a machine with more than one interface? Don't!

But if you have to, you'll soon run into a problem I find completely inexplicable. .NET remoting communications don't necessarily respond to communications on the interface/subnet that initiated those communications.

Imagine you have a machine with two interfaces. One is on subnet 192.168.1.0/24 and the other is on 192.168.2.0/24. Now this machine receives a remoting message on 192.168.1.0/24. .NET may send a reply out the 192.168.1.0/24 interface indicating that all future comms should be handled on the 192.168.2.0/24 interface. All future comms will time out since there is no path between the machines that way. My question is what gives? Why on earth would .NET change what interface to use? In what case does that make any sense at all?

Fortunately, there is a solution. You can bind your remoting channels to a specific interface if you provide the IP of that interface when you create the channel. Here's an example of a channel created bound to an interface.

using System.Runtime.Remoting.Channels.BinaryServerFormatterSinkProvider;
using System.Runtime.Remoting.Channels.Tcp.TcpChannel;

System.Collections.IDictionary dict = new System.Collections.Hashtable();
dict["name"] = "MyChannel";
dict["bindTo"] = "192.168.1.1"; // This is the important bit!
dict["port"] = 67891;
dict["exclusiveAddressUse"] = false; // allows port to be reused if the channel is deleted and recreated

var serverSink = new BinaryServerFormatterSinkProvider();
serverSink.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
TcpChannel serverChannel = new TcpChannel(dict, null, serverSink);

ChannelServices.RegisterChannel(serverChannel);

Now, when an application requests a service from the channel at port 67891, .NET will always talk over the 192.168.1.1 interface.

This really sucks because now you have to specify what interface to use before you can set up your remoting channels. The answers I can think of are to stick it in a config file (which is probably the intended use case since most .NET examples show pretty extensive use of config files), specify it on the command line, or set up a socket that a client must initially connect to so that the app can use the socket API to figure out what interface it needs to talk to the client on. If you know a better way please tell me.

In looking at references while writing this, I've found that the machineName property might be useful for this purpose as well. See the second reference for more info.

Reference:
http://msdn.microsoft.com/en-us/library/bb397831.aspx
http://msdn.microsoft.com/en-us/library/bb397840.aspx

No comments:

Post a Comment