2

複数のクライアント接続を処理し、ゲームの状態に永続的に影響を与える小さなクライアント サーバー ベースのテキスト ゲームを作成しようとしています。コマンドがサーバーに到着した順序で処理されるように、複数の接続を処理する最善の方法は何だろうと思っています。

理想的には、少なくともコマンド処理レベルでは、マルチスレッドを利用するつもりはありません。その後、単一のスレッドで処理を統合できる限り、各クライアントが個別のスレッドを持っていても (各スレッドで IO をブロックするため)、問題ありません。

クライアントとサーバーの間の唯一の通信はテキストであるため、通信をセットアップする最善の方法がわかりません。ブロック IO を選択した場合、単一のスレッドで処理をキューに入れるにはどうすればよいでしょうか?

または、ノンブロッキング IO を選択し、セレクターを使用して、クライアントがサーバーに書き込みを行ったときにクエリを実行する場合、セットサイズの ByteBuffer を使用せずに、長さが不明/無制限の文字列を読み取るにはどうすればよいでしょうか? ノンブロッキングは、クライアント接続が新しいデータを送信するときにクライアント接続から読み取ることができるため、処理を単一のスレッドに保持することにも有利です。ただし、読み取り/書き込みUTFで実装しようとすると、IllegalBlockingModeException hehに遭遇しました。

私が言及していない方法でこれを行う方法に関する質問や提案への回答は、心から感謝します! 私はクライアントとサーバーにかなり慣れていないので、java.io と java.nio のどちらが最も適切かわかりません。

複雑な質問で申し訳ありません。自分で逃げたと思います。

4

2 に答える 2

1

私はサーバークライアントシステムの専門家ではありませんが、いくつかのヒントを共有します

必要に応じて、単純に Tomcat サーバーをセットアップして http 要求を実行できます。これはかなり簡単で、もちろんすべて Java で行います。

欠点は、リクエストが少し遅くなる可能性があることです。

チェックアウトできる 2 番目のオプションは RMI です。

概念は単純で、別のコンピューターに接続し、それが完了したら、コード内のローカル オブジェクトから他のコンピューターのメソッドを呼び出します。

http://java.sun.com/developer/onlineTraining/rmi/RMI.html

少し複雑に見えるかもしれません (また、複数のコンピューターを介してスタックをデバッグするのは少し難しい場合もあります) が、コードを明確に保つため、お勧めします。

最後に、ソケットを試すことができますが、自分で:P

于 2011-04-18T11:44:23.133 に答える
1

意見は異なりますが、私は間違いなくクライアントごとに 1 つのスレッドを使用します。単一の処理スレッドへの通信は、LinkedBlockingQueue または単に同期された LinkedList を介して行うことができます。

クライアントごとのスレッドでは、次のようになります。

public class Client implements Runnable, ResponseOutput {

    private final BufferedReader br;
    private final PrintWriter pw;

    public Client(Socket s) {
        br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        pw = new PrintWriter(s.getOutputStream());
    }

    // defined by the ResponseOutput interface
    public void sendReply(String reply) {
        pw.println(reply);
    }

    public void run() {
        try {
            while (true) {
                String s = br.readLine();
                if (s==null)
                    break;
                Processor.queue(new Processor.InputItem(this, s));
            }
        } catch (IOException ioe) {
            ... error handling ...
        }
    }
}

次に、これを処理します。

public class Processor implements Runnable {
    static public class InputItem {
        final ResponseOutput client;
        final String command;

        public InputItem(ResponseOutput client, String command) {
            this.client = client;
            this.command = command;
        }
    }

    static private Processor instance;
    static public void queue(InputItem item) {
        instance.commandQueue.add(item);
    }

    private BlockingQueue<InputItem> commandQueue;

    public void run() {
        try {
            while (true) {
                InputItem item = commandQueue.take();
                String reply = doStuff(item.command);
                item.client.sendReply(reply);
            }
        } catch (InterruptedException ie) {
            ... error handling ....
        }
    }
}

クラス内にはInputItem、更新が必要なゲーム ステートへの参照を含めることもできます。それを変更するのは処理スレッドだけなので、同期なしでそれを行うことができます。

于 2011-04-18T11:45:45.973 に答える