简体   繁体   English

同一端口上的多个TCP服务器

[英]several TCP-servers on the same port

It looks very strange for me. 对我来说看起来很奇怪。 I can run several TCP servers on the same port. 我可以在同一端口上运行多个TCP服务器。

I use Apache MINA library with following code: 我使用带有以下代码的Apache MINA库:

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

Port 80 is already used by another program. 端口80已被另一个程序使用。 But I didn't get exception "Address already in use". 但是我没有收到异常“地址已在使用中”。 With netstat I can see following: 使用netstat可以看到以下内容:

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. 操作系统:Windows 7。

Thanks. 谢谢。

Normally only one process can listen on a TCP port, on Windows or any other OS (at least the major ones). 通常,只有一个进程可以在Windows或任何其他OS(至少是主要的OS)上的TCP端口上侦听。 On Windows you'd expect to get error code 10048 if two processes share the port. 在Windows上,如果两个进程共享该端口,则期望得到错误代码10048。 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). 如果进程绑定到不同的接口地址(即使一个绑定到INADDR_ANY ,而另一个绑定到一个特定的地址,则它们不会冲突),这将不适用。 Also, this doesn't apply if SO_REUSEADDR has been set on the second socket. 另外,如果已在第二个套接字上设置了SO_REUSEADDR ,则这将不适用。

Since both processes are bound to INADDR_ANY and you claim your process hasn't had SO_REUSEADDR set, however, this is a puzzle. 由于两个进程都绑定到INADDR_ANY并且您声称尚未设置SO_REUSEADDR ,所以这是一个难题。 As far as I can tell there are three possibilities: 据我所知,存在三种可能性:

  1. Something in the underlying library is setting SO_REUSEADDR by default. 默认情况下,基础库中的SO_REUSEADDR设置为SO_REUSEADDR
  2. The second socket was actually opened later and it's the one specifying SO_REUSEADDR . 第二个套接字实际上是稍后打开的,它是指定SO_REUSEADDR的那个。
  3. There is a bug in the Windows sockets layer which allowed this. Windows套接字层中存在一个允许此错误。

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. 我建议您在启动过程之前和之后仔细观察netstat输出,并查看在此之前是否存在其他侦听器。 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). 另外,尝试识别其他进程并查看其是否相关(您可以为此在任务管理器中启用PID列)。

EDIT 编辑

The commenter below has reminded me that I should point out that the behaviour of SO_REUSEADDR does differ across platforms. 下面的评论者提醒我,我应该指出SO_REUSEADDR的行为在不同平台之间确实有所不同。 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 . Windows允许使用强制绑定到同一个端口侦听其它插座,用不确定的行为,如果这两个插座都是TCP,作为讨论的选项新的套接字这里 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. 例如,如果同一端口上的所有套接字都提供TCP服务,则不能保证该端口上的任何传入TCP连接请求都可以由正确的套接字处理-该行为是不确定的。

Linux (and other Unix variants) will not allow two TCP sockets to share the same port if the old one is still listening. 如果旧的Linux套接字仍在侦听,则Linux(和其他Unix变体)将不允许两个TCP套接字共享同一端口。 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). 在这种情况下,如果旧套接字处于TIME_WAIT(也许是FIN_WAIT和CLOSE_WAIT状态,我必须检查一下), SO_REUSEADDR仅允许新套接字绑定。

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. 顺便说一句,当我第一次在Windows中遇到它时,我发现行为上的差异令人惊讶,但我已经对其进行了测试,并且可以肯定的是,如果您在两个套接字上都设置了SO_REUSEADDR ,则很有可能成功绑定到完全相同的地址和端口同时。 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. 我不会进入哪个平台是“正确的”,但是Windows行为肯定会导致安全问题,这就是为什么他们提出SO_EXCLUSIVEADDRUSE选项来防止其他套接字被强制绑定的原因。 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. 我似乎也认为,Windows版本应被视为完全不同的选项,具有不同的行为,而恰好具有相同的名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM