I was tinkering with some C# code that uses
TcpListeners recently, and hit on a strange issue where my code would run fine on on machine, and fail on another. It took me a while to find an answer in Google, so here's a reminder to my future self:
In amongst the code I was running was a fragment like this:
_listener = new TcpListener(IPAddress.Loopback, 1234); _listener.Start();
On my home laptop this ran fine, but on another computer it crashed with an unexpected exception:
For Google's benefit, the stack trace was:
Unhandled exception. System.Net.Sockets.SocketException (10013): An attempt was made to access a socket in a way forbidden by its access permissions. at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName) at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) at System.Net.Sockets.Socket.Bind(EndPoint localEP) at System.Net.Sockets.TcpListener.Start(Int32 backlog) at System.Net.Sockets.TcpListener.Start() at Channels.ConnectionListener.Start() in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\ConnectionListener.cs:line 24 at Channels.Wrapper.Start() in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\Wrapper.cs:line 24 at Channels.Program.Main(String args) in C:\Users\JDavis\Source\Repos\ChannelsExperiment\Channels\Program.cs:line 23 at Channels.Program.<Main>(String args)
My initial thought was "ah, there'll be something else using that port..." but running
didn't show a hit against the loopback address I was trying to bind:
Active Connections Proto Local Address Foreign Address State PID TCP 127.0.0.1:1029 127.0.0.1:1030 ESTABLISHED 5604 TCP 127.0.0.1:1030 127.0.0.1:1029 ESTABLISHED 5604 TCP 127.0.0.1:1715 127.0.0.1:1716 ESTABLISHED 5604 TCP 127.0.0.1:1716 127.0.0.1:1715 ESTABLISHED 5604 TCP 127.0.0.1:1763 127.0.0.1:62522 ESTABLISHED 10852 TCP 127.0.0.1:62522 127.0.0.1:1763 ESTABLISHED 4780
(I checked against the real IP address of the machine as well – nothing there either)
So I fell back on "it was a security error – maybe I have fewer rights on this machine?" and tried running Visual Studio (and also my test app) as admin. But no difference there either.
After a pile of futher googling I hit upon an idea that was entirely new to me. It turns out code can reserve a port, without ever actually opening it. That means Windows will refuse you rights to use it for anything else – but it won't show up on the netstat call shown above. And the refusal comes up as the odd security error above.
To work this out you need a different command:
netsh interface ipv4 show excludedportrange protocol=tcp
and for me that gives:
Protocol tcp Port Exclusion Ranges Start Port End Port ---------- -------- 1132 1231 1232 1331 1435 1534 1555 1654 1819 1918 50000 50059 * * - Administered port exclusions.
My code tried to open port 1234, and that is included in the second of these ranges... Bingo!
The critical info here came from this Stack Overflow answer, if you want to read the original source.
So I can use this info to pick a port that's free on all my machines, and my little bit of test code can run happily.