Java服务器 - 多个端口?

问题描述 投票:11回答:5

我正准备编写一个服务器的程序,但我想知道我的想法是否可行。我的程序将在多个端口上输出到多个客户端 - 每个端口可以被多个客户端访问。

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

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

希望这有一定的意义,你能明白我想做什么。简单的说就是:监听选定的端口,根据连接到哪个端口,创建一个线程socket连接。

这样做是否完全可行,还是说我最终要用多线程的套接字服务器?

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

java multithreading tcp serversocket
5个回答
15
投票

对于一个单一实例的 ServerSocket 来监听多个端口。当然,您也可以有多个 ServerSockets. 然而,你已经知道。ServerSocket.accept 块。

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

如果没有挂起的连接,当 ServerSocketChannel.accept 调用,那么它就会简单地返回null。

你可以用 Selector 这需要一组通道,并阻止,直到至少有一个有一个挂起的连接。

我不记得如何使用它们的具体细节了,但 这个 似乎是一个不错的代码例子。

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

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

11
投票

你好所以,让我直说吧。你要做的是创建一个可以监听多个端口的服务器,当你得到一个新的连接时,你想知道这个连接使用的是哪个端口,是这样吗?如果是这样的话,你可以很容易地通过使用 java.nio 包。

我们将使用一个 选择器 甄选准备工作和 服务器插座通道 来监听传入的连接。

首先我们需要声明我们的 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语句,但这是为了方便阅读和理解。

记住,这个服务器是以非阻塞异步的方式来设置的,这样你执行的所有IO调用都不会阻塞当前线程。所以 切勿 发起任何新线程 SelectionKey 处理过程。

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


1
投票

你不能在多个端口监听 端口,但你可以监听其中的一组端口。创建一个 ServerSocket ( http:/download.oracle.comjavase6docsapijavanetServerSocket.html#ServerSocket%28int%29。 )为每个你想监听的端口设置一个线程,并在每个端口上接受连接。


1
投票

这在NIO中应该是可行的,但是我没有看到一个很好的理由来避免每个监听器只有一个线程,除非你有超过1K的端口。

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


-1
投票

我不认为你可以监听所有的端口,不。对操作系统来说,这样做的成本相当高,所以端口监听根本不是这样工作的。

如果多个应用程序同时监听 "所有 "端口,那么网络子系统应该将传入的数据包传送给哪个应用程序呢?

© www.soinside.com 2019 - 2024. All rights reserved.