Finding Free Ports
One of the options for the listen URI for the TCP transport is to let the transport make the address unique by filling in details such as the port number. The socket API allows specifying a wildcard port but at the time WCF was written the wildcard port option could only be used with a single IP version. Since WCF listens on both IPv4 and IPv6 addresses, how did this work?
First, there are several cases where the process is simple. If the network stack only supports a single IP version, for example if IPv6 is not installed, then we don’t have to do anything special to get a wildcard port. Similarly, if the address you’re listening on is specified as an IP address, then we don’t need to worry about IP protocol versions besides the one you picked since we’ll only be listening on that specific address.
If we find that both IPv4 and IPv6 are allowed and you asked for a unique port, then that is the case where we actually have a problem. The solution we chose is brute force. We start by generating ten random numbers between 49152 and 65535. Then, we try binding sockets for each of our randomly chosen ports until we find one that works for both IPv4 and IPv6. This means that there’s a chance we’ll give up and say that there are no free ports even when some are unused.
The chances of giving up too soon are negligible for the first 5000 ports. By the time you get to 10,000 unique open ports though, the chances of giving up are in the neighborhood of 1%. It only gets worse from there as by the time you get to 15,000 unique open ports you’ll be seeing failures about half the time.
Comments
Anonymous
July 23, 2009
When you create a ServiceHost that is using a unique port, how do you determine which port it is actually using? We are trying to create a subscribe mechanism where the client will start a ServiceHost, determine the listening address and then send that information in a request to a well known endpoint so it can push updates to the client.Anonymous
July 29, 2009
Hi Robert, Once the channel listener has been built from the binding you can look at the Uri on the listener.