.Net Remoting and IPv6

.Net Remoting is quite an old technology, and has been superseded by Windows Communication Foundation in .Net 3.0. However, that doesn’t mean it’s useless; you may have an old application that already uses it, or you may need to target clients that don’t have .Net 3.0, or maybe you’re even working with Mono, which currently doesn’t support WCF. In all these scenarios, using .Net Remoting is still perfectly valid.

.Net Remoting was introduced in .Net 1.0, and broad support for IPv6 was not introduced until .Net 2.0. For reasons of backwards compatibility, a .Net Remoting server still listens on IPv4 by default, even in .Net 2.0 and higher. Only if your networking configuration supports only IPv6 (IPv4 is disabled completely) will .Net Remoting automatically listen on IPv6.

It seems like that should be fine. After all, if your network supports IPv4, what is the problem with using it? It turns out there is one, and it’s quite subtle. If your network is configured to use both IPv6 and IPv4, and your Remoting clients are using host names to connect to the server, those host names will resolve to both an IPv6 and IPv4 address. Windows will then try to connect using IPv6 first – which fails because the server is listening only on IPv4 – causing a delay of a few seconds on the initial connection.

You can easily reproduce this problem by having a .Net Remoting client connect to a server on the local host on a computer running Vista with the default networking setup which has IPv6 enabled. If you use localhost in the well-known service URL it will attempt IPv6 first, causing a delay. If instead you use it will be much quicker. However, using IP addresses instead of host names may not be practical, and disabling IPv6 is also a bit of a sledgehammer solution. A better idea is to make .Net Remoting listen on IPv6.

Although it can be rather hard to find out how to do this from the documentation, it turns out to be quite simple. If you use the app.config file to configure remoting you can use the bindTo attribute of the channel to listen on IPv6. If you just add that attribute, the server will no longer listen on IPv4 however; if you want both IPv4 and IPv6, you need to define two channels. An example is given below:

      <wellknown mode="Singleton" type="MyApplication.MyServer, MyAssembly" objectUri="MyServer" />
      <channel ref="tcp" name="tcp6" port="9000" bindTo="[::]" />
      <channel ref="tcp" name="tcp4" port="9000" bindTo="" />

As you can see, the IPv6 addresses are enclosed in square brackets. By using [::], the server will listen on all IPv6 addresses; you can of course also specify an explicit IPv6 address to listen on, same as for IPv4. For example, [::1] would cause it to listen on the local host only. This example uses a TCP channel, but the same principle works for HTTP channels as well.

If you configure remoting programmatically, you can use the same approach:

IDictionary properties = new Hashtable();
properties["name"] = "tcp6";
properties["port"] = 9000;
properties["bindTo"] = "[::]";
TcpServerChannel channel = new TcpServerChannel(properties, null);
ChannelServices.RegisterChannel(channel,  false);

Again, if you need it to listen on both IPv6 and IPv4, you need to configure two channels. The client does not need to be changed at all, for both methods of configuration.

A small note for people who are using Mono: on Linux, if you bind to an IPv6 address, it will automatically bind to the equivalent IPv4 address as well. In that case, you don’t need to specify two channels, just create a channel for IPv6 and it will listen on IPv4 too. This behaviour is exclusive to Linux, other flavours of Unix (e.g. FreeBSD) don’t do it.

Categories: Programming
Posted on: 2009-01-03 08:19 UTC.


Miguel Ventura

2009-06-16 13:46 UTC

Good tip! Thanks a lot :)

Add comment

Comments are closed for this post. Sorry.

Latest posts




RSS Subscribe