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

标签 java tcp apache-mina

我觉得很奇怪。我可以在同一端口上运行多个 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。

谢谢。

最佳答案

在 Windows 或任何其他操作系统(至少是主要操作系统)上,通常只有一个进程可以监听 TCP 端口。在 Windows 上,如果两个进程共享端口,您会收到错误代码 10048。如果进程绑定(bind)到不同的接口(interface)地址,这将不适用(即使一个进程绑定(bind)到 INADDR_ANY 而另一个绑定(bind)到特定地址,它们不会冲突)。此外,这不适用于 SO_REUSEADDR。已设置在第二个套接字上。

由于这两个进程都绑定(bind)到 INADDR_ANY 并且您声称您的进程没有设置 SO_REUSEADDR,但是,这是一个难题。据我所知,存在三种可能性:

  1. 底层库中的某些东西默认设置 SO_REUSEADDR
  2. 第二个套接字实际上是稍后打开的,它是指定 SO_REUSEADDR 的套接字。
  3. Windows 套接字层中存在允许这样做的错误。

我意识到没有软件是完美的,但我真的很犹豫是否选择第三个选项,尤其是如果您可以轻松地复制它。我建议在开始您的进程之前和之后仔细观察 netstat 输出,并查看在此之前是否存在其他监听器。此外,尝试识别其他进程并查看它是否相关(您可以为此在任务管理器中启用 PID 列)。

编辑

下面的评论者提醒我,我应该指出 SO_REUSEADDR 的行为确实因平台而异。 Windows 允许新套接字使用强制绑定(bind)到与其他监听套接字相同的端口的选项,如果两个套接字都是 TCP,则行为不确定,如所讨论的 here .实际上,第二个套接字可能会“窃取”地址,但官方说法似乎是行为未定义:

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(和其他 Unix 变体)将不允许两个 TCP 套接字共享同一个端口,如果旧套接字仍在监听的话。在这种情况下,SO_REUSEADDR 仅在旧套接字处于 TIME_WAIT 时才允许绑定(bind)新套接字(也许 FIN_WAIT 和 CLOSE_WAIT 状态,我必须检查一下)。

顺便说一句,当我第一次在 Windows 中遇到它时,我发现行为上的差异非常令人惊讶,但我自己测试过,当然如果你在两个套接字上设置 SO_REUSEADDR 很可能同时成功绑定(bind)到完全相同的地址和端口。但是,我没有对这种情况下的确切行为进行广泛的测试,因为在我的情况下这并不重要。

我不想讨论哪个平台是“正确的”,但 Windows 的行为肯定会导致安全问题,这就是为什么他们想出了 SO_EXCLUSIVEADDRUSE 选项来强制阻止其他套接字捆绑。我似乎也有人认为 Windows 版本应该被视为一个完全不同的选项,具有不同的行为,恰好具有相同的名称。

关于java - 同一端口上的多个 TCP 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13567361/

相关文章:

java - 使用 Hibernate 建模 Java 类的最佳实践是什么?

java - 添加两个列表并以嵌套形式获取 XML 输出

java - 使用 Apache Mina 通过 UDP 将数据发送回客户端

Java MINA 暴露套接字

java - 带有 OneToMany 的 Spring Data Projection 返回太多结果

java - WebView 和 SSLSocket

ios - UDP是否适合从iOS传输离散事件

php - 使用 select() 的简单 TCP 服务器,为什么 "longest request"这么高?

c++ - 在特定网络接口(interface) Linux/Unix 上使用 C++ TCP 客户端套接字

java - 如何通过MINA正确发送数据?