【问题标题】:Java Server - Multiple ports?Java 服务器 - 多个端口?
【发布时间】:2011-02-22 14:08:06
【问题描述】:

我即将对服务器进行编程,但我想知道我的想法是否可行。我的程序将输出到多个端口上的多个客户端 - 每个端口都可以被多个客户端访问。

通常我会使用线程套接字服务器,但在这种情况下,我需要它为多个端口工作。我想到的用法是在下面的模糊伪代码中:

  • 启动服务器
  • 监听多个端口的传入连接
  • 识别连接的端口
    • 如果端口1,启动一个线程监听客户端并输出消息类型x
    • 如果是端口2,启动一个线程监听客户端并输出消息类型y

希望这是有道理的,你可以看到我想要做什么。简单来说:监听选定的端口,根据正在连接的端口创建线程套接字连接。

这是可行的,还是我最终会使用多线程线程套接字服务器?

编辑:更改措辞以更好地反映问题。

【问题讨论】:

  • 我知道你已经选择了你接受的答案,但请看看我的答案,也许重新考虑一下。

标签: java multithreading tcp serversocket


【解决方案1】:

ServerSocket 的单个实例无法监听多个端口。你当然可以有多个ServerSockets。但是,正如您所知,ServerSocket.accept 会阻止。

您可以改用ServerSocketChannel。它们的使用方式类似,但不要阻塞。

如果在调用 ServerSocketChannel.accept 时没有挂起的连接,则它只返回 null。

您可以使用Selector,它采用一组通道和阻塞,直到至少有一个具有挂起的连接。

我不记得如何使用它们的细节,但this 似乎是一个不错的代码示例。

编辑:这是我自己的例子(伪)

Selector selector = Selector.open();

int[] ports = {4000,4001,6000};

for (int port : ports) {
   ServerSocketChannel server = ServerSocketChannel.open();
   server.configureBlocking(false);

   server.socket().bind(new InetSocketAddress(port));
// we are only interested when accept evens occur on this socket
   server.register(selector, SelectionKey.OP_ACCEPT); 
}

while (selector.isOpen()) {
   selector.select();
   Set readyKeys = selector.selectedKeys();
   Iterator iterator = readyKeys.iterator();
   while (iterator.hasNext()) {
      SelectionKey key = (SelectionKey) iterator.next();
      if (key.isAcceptable()) {
         SocketChannel client = server.accept();
         Socket socket = client.socket();
// create new thread to deal with connection (closing both socket and client when done)
      }
   }
}

// tidy up selector and channels

【讨论】:

  • 有趣.. 正如你所说,它会阻塞,这是我打算使用多线程线程服务器的主要原因。给我几分钟看看这个...
  • 嗯,绝对不是我想的那样;我的目标是能够监听一组特定的端口(不一定使用“ServerSocket”),但这似乎是朝着正确方向迈出的一步。谢谢大家,如果我能给出一个以上的最佳答案,我会的,尤其是 Vance Maverick,但谢谢 Dunes。
  • 不确定您的问题是什么。将编写我自己的伪示例,看看是否可以解决问题。
  • 我想我明白了……如果我的理解是正确的,程序将开始监听一个端口,但继续运行程序,监听所有指定的端口。当在这些端口之一上检测到连接时,将创建线程来处理它。这是一个公平的假设吗?再次感谢沙丘。
  • 您的代码需要调整才能正常工作。您无权访问 while 循环中的 server 变量。 accept 可以从关键对象完成:SocketChannel client = ((ServerSocketChannel)key.channel()).accept(); 编译所需的导入是:java.net.*; java.io.*; java.nio.*; java.nio.channels.*; java.util.*;
【解决方案2】:

你好,让我直说吧。您要做的是创建一个可以侦听多个端口的服务器,并且当您获得新连接时,您希望能够知道该连接使用了哪个端口,这是正确的吗?如果是这样的话,您可以使用 java.nio 包轻松完成此操作。

我们将使用Selector 进行就绪选择,并使用ServerSocketChannel 侦听传入连接。

首先我们需要声明我们的Selector

Selector selector = Selector.open();

现在让我们创建一个要监听的端口列表并开始监听它们。

int ports[] = new int[] { 1234, 4321 };

// loop through each port in our list and bind it to a ServerSocketChannel
for (int port : ports) {
    ServerSocketChannel serverChannel = ServerSocketChannel.open();
    serverChannel.configureBlocking(false);
    serverChannel.socket().bind(new InetSocketAddress(port));
    serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}

现在是SelectionKey 处理过程。

while (true) {
    selector.select();

    Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
    while (selectedKeys.hasNext()) {
        SelectionKey selectedKey = selectedKeys.next();

        if (selectedKey.isAcceptable()) {
            SocketChannel socketChannel = ((ServerSocketChannel) selectedKey.channel()).accept();
            socketChannel.configureBlocking(false);
            switch (socketChannel.socket().getPort()) {
                case 1234:
                    // handle connection for the first port (1234)
                    break;
                case 4321:
                    // handle connection for the secon port (4321)
                    break;
            }
        } else if (selectedKey.isReadable()) {
            // yada yada yada
        }
    }
}

对于这样一个简单的任务,可能不需要 switch 语句,但它是为了便于阅读和理解。

请记住,此服务器以非阻塞异步方式设置,因此您执行的所有 I/O 调用都不会阻塞当前线程。所以不要SelectionKey处理过程中启动任何新线程。

另外,我知道这并不能完全回答您的问题(它可能会,也可能不会),但它实际上会让您了解如何使用 java.nio 包创建非阻塞异步服务器可以监听多个端口。

【讨论】:

  • 我正在关注此代码并在调用 serverchannel 上的注册函数的行上收到 IllegalBlockingmodeException。
  • socketChannel.socket().getPort() 当数据从客户端发送到服务器时返回新的端口号!你必须改写socketChannel.socket().getLocalPort()
【解决方案3】:

您无法监听所有端口,但可以监听其中的一组。为您要侦听的每个端口创建一个 ServerSocket (http://download.oracle.com/javase/6/docs/api/java/net/ServerSocket.html#ServerSocket%28int%29),并接受每个端口上的连接。

【讨论】:

  • 是的,这就是我所说的多线程线程服务器的意思——我想我可能的意思是我想要一种更有效的方式来监听一组端口。
【解决方案4】:

这应该可以通过 NIO 实现,但是我认为没有充分的理由避免每个侦听器使用一个线程,除非您有超过 1K 的端口。

您真的需要多个监听端口吗?在大多数情况下,一个端口应该可以支持所有类型的客户端并让客户端告诉服务器(或服务器确定需要哪种类型的连接)

【讨论】:

  • 这是我的观点,区分请求类型并不是应该使用的端口。请求路径是正确的方法。这里的客户的性质是什么?
  • 这主要是为了允许以后内置额外的功能。例如。如果为端口 3000 引入消息类型 z,则不需要有人去弄乱服务器代码。我的计划是有一个配置文件,服务器将在其中读取要为哪些端口输出的消息类型。至于是否需要多个监听端口,在这种情况下,有高级工程师的具体要求。
  • 看来您希望通过端口硬编码订阅消息组。这通常通过客户端发送的协议版本或协议类型来完成。 (但我有一个使用服务器上的两个端口执行此操作的示例,因此我可以使用普通 telnet 到端口查看数据,所以我不反对)
  • @PeterLawrey 是否可以在单个端口上运行多个 SocketChannel,即相同的 SocketAddress?
  • 一个 SocketChannel 有两个 IP:port 组合,每个组合一个。每个连接都必须是唯一的。对于一个 IP:port,您可以从不同的 IP:ports 连接多次。
【解决方案5】:

我不认为你可以监听所有端口,不。对于操作系统来说,这将是相当昂贵的实现,所以这根本不是端口监听的工作原理。

如果多个应用程序同时监听“所有”端口,网络子系统应将传入数据包传递到哪个应用程序?

【讨论】:

  • 嗯,这就是我所担心的......而且大概是监听少数几个端口的最有效方式,假设我知道我只会有人连接到端口 4000、4010、4020,或者4030,会是多线程一个线程套接字服务器吗?
  • 多线程线程套接字服务器?我不明白这个。
  • “多线程线程套接字服务器”,应该是。我的意思是,创建一个侦听端口的线程套接字服务器,例如 4000,创建一个侦听端口 4010 等的线程套接字服务器,并多线程这些以使服务器同时运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-28
  • 2011-02-20
  • 2021-07-10
  • 2019-05-26
  • 2014-05-28
  • 2021-02-14
  • 2015-02-10
相关资源
最近更新 更多