12

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

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

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

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

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

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

4

5 回答 5

15

单个实例不可能ServerSocket监听多个端口。你当然可以有多个ServerSockets. 但是,正如您已经知道的那样,ServerSocket.accept块。

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

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

您可以与 a 一起使用,Selector它需要一组通道和块,直到至少一个具有挂起的连接。

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

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

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
于 2011-02-22T14:35:20.420 回答
12

你好,所以让我直截了当。您要做的是创建一个可以侦听多个端口的服务器,并且当您获得新连接时,您希望能够知道该连接使用了哪个端口,这是正确的吗?好吧,如果是这种情况,您可以使用该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包创建可以侦听多个端口的非阻塞异步服务器.

于 2011-03-22T01:38:36.337 回答
1

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

于 2011-02-22T14:24:18.853 回答
1

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

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

于 2011-02-22T14:25:47.217 回答
-1

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

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

于 2011-02-22T14:11:51.723 回答