对我来说这看起来很奇怪。我可以在同一个端口上运行多个TCP服务器。
我使用Apache MINA库以及以下代码:
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.bind(new InetSocketAddress(80));
端口80已被其他程序使用。但我没有得到异常“地址已经在使用中”。使用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
有人能解释我这样的行为吗?
操作系统:Windows 7。
感谢。
答案 0 :(得分:2)
通常只有一个进程可以侦听TCP端口,Windows或任何其他操作系统(至少是主要的)。在Windows上,如果两个进程共享端口,您可能会收到错误代码10048。如果进程绑定到不同的接口地址(即使一个绑定到INADDR_ANY
而另一个绑定到特定地址,它们不会发生冲突),这将不适用。此外,如果在第二个套接字上设置了SO_REUSEADDR
,则不适用。
由于这两个进程都绑定到INADDR_ANY
并且您声称您的进程未设置SO_REUSEADDR
,因此,这是一个难题。据我所知,有三种可能性:
SO_REUSEADDR
。SO_REUSEADDR
。我意识到没有软件是完美的,但我真的不愿意选择第三种选择,特别是如果你可以轻松地重现它。我建议在开始进程之前和之后仔细观察netstat
输出,并在此之前查看另一个侦听器是否存在。此外,尝试识别其他进程并查看它是否相关(您可以在任务管理器中启用PID列)。
修改强>
下面的评论者提醒我,我应该指出SO_REUSEADDR
的行为确实因平台而异。 Windows允许使用该选项的新套接字强制绑定到与其他侦听套接字相同的端口,如果两个套接字都是TCP,则具有未确定的行为,如here所述。在实践中,第二个插槽可能“窃取”了地址,但官方线似乎是行为未定义:
第二个套接字成功绑定后,绑定到该端口的所有套接字的行为都是不确定的。例如,如果同一端口上的所有套接字都提供TCP服务,则无法保证端口上的任何传入TCP连接请求都由正确的套接字处理 - 行为是不确定的。
Linux(和其他Unix变体)不允许两个TCP套接字共享同一端口(如果旧端口仍在侦听)。在这种情况下,SO_REUSEADDR
仅允许新套接字绑定(如果旧套接字处于TIME_WAIT(可能是FIN_WAIT和CLOSE_WAIT状态,我必须检查)。
顺便说一句,当我第一次在Windows中遇到它时,我发现行为上的差异非常令人惊讶,但我自己测试了它,当然如果你在两个套接字上设置SO_REUSEADDR
,它很可能成功绑定同时完全相同的地址和端口。然而,我没有对这种情况下的确切行为进行过广泛的测试,因为在我的情况下,这并不重要。
我不打算进入哪个平台“正确”,但肯定Windows行为导致安全问题,这就是为什么他们提出SO_EXCLUSIVEADDRUSE
选项以防止其他套接字强行绑定的原因。我也似乎有人认为Windows版本应该被视为一个完全不同的选项,具有不同的行为,恰好具有相同的名称。