它看起来非常奇怪我。 我可以在同一端口上运行多个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。
谢谢。
通常情况下只有一个进程可以听一个TCP端口,在Windows或任何其他操作系统(至少是主要的)。 在Windows上,你希望得到错误代码10048如果两个进程共享端口。 如果进程被绑定到不同的接口地址(即使其中一个被绑定到这不适INADDR_ANY
,另一种是绑定到特定的地址,他们不冲突)。 另外,如果这并不适用SO_REUSEADDR
已经在第二插座上进行设置。
由于这两个过程都必然INADDR_ANY
,你要求你的进程一直没有SO_REUSEADDR
集,但是,这是一个谜。 至于我可以告诉大家有三种可能性:
- 一些底层库设置
SO_REUSEADDR
默认。 - 第二插座竟是后来开了,它是一个指定
SO_REUSEADDR
。 - 有一个在这为本的Windows套接字层的错误。
我意识到没有软件是完美的,但我真的毫不犹豫地选择了第三个选项,特别是如果你可以很容易地复制它。 我会仔细看提示netstat
前开始你的过程中,看到是否在此之前,其他听众存在后输出。 此外,试图找出其他进程,看看是否它的相关(您可以启用该任务管理器的PID列)。
编辑
下面的评论者提醒我,我要指出的是行为SO_REUSEADDR
不跨平台有所不同。 Windows允许使用的选项强制绑定到同一端口的其它监听插槽,不确定的行为,如果这两个插座都是TCP,所讨论的新的套接字这里 。 在实践中,第二插座可能是“偷”的地址,但官网上似乎是这种行为是未定义:
一旦第二座已成功绑定,绑定到该端口的套接字的行为是不确定的。 例如,如果所有的同一个端口上的插座提供TCP服务,在任何端口传入的TCP连接请求,不能保证被正确的插座来处理 - 的行为是不确定性。
Linux(和其他Unix变种)将不会允许两个TCP套接字共享同一端口,如果旧的还在听。 在这种情况下, SO_REUSEADDR
只允许新的socket绑定如果旧的一个是在TIME_WAIT(或许FIN_WAIT和CLOSE_WAIT状态,我必须检查)。
顺便说一句,我发现在行为的差异相当令人惊讶,当我第一次在Windows碰到它,但我已经测试它自己,当然,如果你设置SO_REUSEADDR
两个插座上它很可能成功地绑定到完全相同的地址和端口同时。 我没有做过确切的行为广泛的测试在这种情况下,然而,因为在我的情况下,它并没有太大的关系。
我不是要进入哪个平台是“正确的”,但肯定在Windows行为导致这就是为什么他们想出了一个安全问题SO_EXCLUSIVEADDRUSE
选项,以防止其他套接字强制约束力。 我也似乎是Windows版本应该被视为一个完全不同的选择,不同的行为,这恰好具有相同名称的意见的人。