12

サーバーをプログラミングしようとしていますが、考えていることが可能かどうか疑問に思っています。私のプログラムは、複数のポートで複数のクライアントに出力します。各ポートには複数のクライアントがアクセスできます。

通常はスレッド化されたソケット サーバーを使用しますが、この場合は複数のポートで動作する必要があります。私が念頭に置いている使用法は、以下の漠然とした擬似コードです。

  • サーバーを起動
  • 複数のポートで着信接続をリッスンする
  • 接続されているポートを特定する
    • ポート 1 の場合、クライアントをリッスンしてメッセージ タイプを出力するスレッドを開始しますx
    • ポート 2 の場合、クライアントをリッスンしてメッセージ タイプを出力するスレッドを開始しますy

うまくいけば、それはある程度の意味があり、私がやろうとしていることを見ることができます. 簡単に言えば、選択したポートをリッスンし、接続先のポートに基づいてスレッド化されたソケット接続を作成します。

これはまったく実行可能ですか、それともマルチスレッドのスレッド化されたソケット サーバーになるのでしょうか?

編集:質問をよりよく反映するように文言を変更しました。

4

5 に答える 5

15

の 1 つのインスタンスでServerSocket複数のポートをリッスンすることはできません。もちろん複数持つこともできますServerSocket。ただし、ご存知のように、ServerSocket.acceptブロックします。

代わりに使用できるのはServerSocketChannel. それらは同様の方法で使用されますが、ブロックしません。

が呼び出されたときに保留中の接続がない場合ServerSocketChannel.acceptは、単に null を返します。

Selector少なくとも 1 つが保留中の接続を持つまで、一連のチャネルとブロックを取得する と一緒に使用できます。

それらの使用方法の詳細は覚えていませんが、これはまともなコード例のようです。

編集:これは私自身の例です(疑似っぽい)

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パッケージを使用してこれを非常に簡単に行うことができます。

準備の選択にはセレクターを使用し、着信接続をリッスンするには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

すべてのポートをリッスンすることはできませんが、一連のポートをリッスンできます。リッスンするポートごとに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 を超える場合を除き、リスナーごとに 1 つのスレッドを使用しないようにする正当な理由はありません。

複数のリスニング ポートが本当に必要ですか。ほとんどの場合、1 つのポートですべての種類のクライアントをサポートし、クライアントがサーバーに通知する (またはサーバーが必要な接続の種類を決定する) ことが可能です。

于 2011-02-22T14:25:47.217 に答える
-1

すべてのポートをリッスンできるとは思いません。これは、OS が実装するのに非常にコストがかかるため、ポート リッスンが機能する方法ではありません。

複数のアプリケーションが「すべての」ポートを同時にリッスンしている場合、ネットワーク サブシステムはどのアプリケーションに着信パケットを配信する必要があるでしょうか?

于 2011-02-22T14:11:51.723 に答える