several TCP-servers on the same port
Asked Answered
M

1

6

It looks very strange for me. I can run several TCP servers on the same port.

I use Apache MINA library with following code:

IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.bind(new InetSocketAddress(80));

Port 80 is already used by another program. But I didn't get exception "Address already in use". With netstat I can see following:

C:\>netstat -oan |find /i "LIST"
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       2220
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       904
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       840

Could someone explain me such behaviour?

OS: Windows 7.

Thanks.

Mullein answered 26/11, 2012 at 14:55 Comment(6)
What are processes 2220 and 904? And was port 80 in use before you bound to it? Or did your bind result in it being shared by two processes whereas before it was closed? Do you call setReuseAddress?Fellers
@trashgod There is nothing at that link that explains this behaviour. This is not supposed to happen.Plutonic
2220 is javaw (my app). 904 is skype (was launched before). I didn't call setReuseAddress.Mullein
I think more than one app can listen to incoming connections, but when there finally is an incoming connection, only one can connect.Airt
You found the holy grail. We can finally run web servers without needing a separate IP per certiciate or TLS 1.2 with SNI... Okay, to be true, this output looks very wrong to me. Two processes listening on the same host, port and protocol should not be possible.Quintanilla
As I've explained in my answer and comments below, it's possible on Windows - however, it should still require SO_REUSEADDR so this behaviour is still puzzling since the OP claims not to have specified that option. See my answer for more details.Rigel
R
3

Normally only one process can listen on a TCP port, on Windows or any other OS (at least the major ones). On Windows you'd expect to get error code 10048 if two processes share the port. This won't apply if the processes are bound to different interface addresses (even if one is bound to INADDR_ANY and the other is bound to a specific address, they don't clash). Also, this doesn't apply if SO_REUSEADDR has been set on the second socket.

Since both processes are bound to INADDR_ANY and you claim your process hasn't had SO_REUSEADDR set, however, this is a puzzle. As far as I can tell there are three possibilities:

  1. Something in the underlying library is setting SO_REUSEADDR by default.
  2. The second socket was actually opened later and it's the one specifying SO_REUSEADDR.
  3. There is a bug in the Windows sockets layer which allowed this.

I realise no software is perfect, but I really hesitate to choose the third option, especially if you can easily reproduce it. I would suggest carefully watching netstat output before and after starting your process and seeing whether the other listener exists prior to that. Also, try to identify the other process and see whether it's related (you can enable the PID column in the task manager for that).

EDIT

The commenter below has reminded me that I should point out that the behaviour of SO_REUSEADDR does differ across platforms. Windows allows new sockets using the option to forcibly bind to the same port as other listening sockets, with undetermined behaviour if the two sockets are both TCP, as discussed here. In practice the second socket probably "steals" the address, but the official line seems to be that the behaviour is undefined:

Once the second socket has successfully bound, the behavior for all sockets bound to that port is indeterminate. For example, if all of the sockets on the same port provide TCP service, any incoming TCP connection requests over the port cannot be guaranteed to be handled by the correct socket — the behavior is non-deterministic.

Linux (and other Unix variants) will not allow two TCP sockets to share the same port if the old one is still listening. In this case, SO_REUSEADDR only allows the new socket to bind if the old one is in TIME_WAIT (and perhaps the FIN_WAIT and CLOSE_WAIT states, I'd have to check that).

As an aside, I found the difference in behaviour quite surprising when I first came across it in Windows, but I've tested it myself and certainly if you set SO_REUSEADDR on both sockets it's quite possibly to bind successfully to exactly the same address and port simultaneously. I haven't done extensive testing on the exact behaviour in this situation, however, since in my case it didn't matter too much.

I'm not about to get into which platform is "correct", but certainly the Windows behaviour has lead to security issues which is why they came up with the SO_EXCLUSIVEADDRUSE option to prevent other sockets forcibly binding. I've also seem people of the opinion that the Windows version should be regarded as a completely different option, with different behaviour, which just happens to have the same name.

Rigel answered 2/2, 2013 at 1:23 Comment(3)
4. There is a bug in netstat which shows this erroneously. You can't bind a TCP socket to the same IP:port, with or without SO_REUSEADDR. That's for UDP.Plutonic
At least on Windows you can bind to the same port if you use SO_REUSEADDR even if the first socket is active, but it isn't defined which socket receives the connection. Take a look at this MSDN page and scroll down to the "Using SO_EXCLUSIVEADDRUSE" section and look at the table of which pairs of bind() calls are permitted. The text mentions it applies to XP and earlier, but if you read further you'll see this is just because Vista and extend the same checks for dual-stack (IPv4 and IPv6) applications.Rigel
An additional quote from the page I just linked which describes the behaviour with SO_REUSEADDR under Windows: Once the second socket has successfully bound, the behavior for all sockets bound to that port is indeterminate. For example, if all of the sockets on the same port provide TCP service, any incoming TCP connection requests over the port cannot be guaranteed to be handled by the correct socket — the behavior is non-deterministic.Rigel

© 2022 - 2024 — McMap. All rights reserved.