0

私はマルチプレイヤー ゲームを作成しており、ソケットを使用して Java で独自のサーバーを作成しています。

Javaチュートリアルといくつかのグーグルを使用してサーバーを正常に稼働させることができましたが、複数のクライアントを処理するためにマルチスレッドサーバーを実装しようとすると、うまく機能しません.

接続する最初のクライアントは引き続き正常に動作しますが、接続する他のクライアントはそのまま待機し、サーバーに入力を送信した後は何もしません。これが私のコードです:

//This class handled Server/client communication for one client.
public class GameRoom implements Runnable {
  public GameRoom(Socket socket) {
    this.socket = socket;
  }

  public void run() {
    logger.info("Game room has been created.");

    while(true) {
      try {
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        out = new PrintWriter(socket.getOutputStream());
        String clientResponse = in.readLine();
        out.println("You wrote " + clientResponse);
        out.flush();
      } catch (IOException e) {
        logger.severe(e.getMessage());
        throw new RuntimeException();
      }
    }
  }

  //Will eventually change the string to a GSON object and delegate the appropriate actions based on the gson object type.
  private String delegateClientInput(String clientInput) {
    return "I heard you say: " + clientInput + "\n";
  }

  private BufferedReader in;
  private PrintWriter out;
  private Socket socket;
  private static final Logger logger = LogUtil.initializeServerLog(GameRoom.class.toString());
}

/*
 * This class houses the server socket itself.  Handles connecting to multiple clients.
 */
public class ServerClientThreadPool extends Thread {
  public static void main(String[] args) {
    ServerClientThreadPool serverClientThreadPool = new ServerClientThreadPool();
    serverClientThreadPool.startServer();
  }

  ServerClientThreadPool() {
    try {
      serverListener = new ServerSocket(GAME_ROOM_PORT);
    } catch (IOException e) {
      logger.severe(e.getMessage());
      throw new RuntimeException();
    }
  }

  public void startServer() {
    for(int i = 0; i < MAX_CONNECTIONS; i++) {
      try {
        GameRoom gameRoom = new GameRoom(serverListener.accept());
        gameRoom.run();
      } catch (IOException e) {
        logger.severe(e.getMessage());
        throw new RuntimeException();
      }
    }
  }

  private static final int GAME_ROOM_PORT = 18000;
  private ServerSocket serverListener;
  private static final int MAX_CONNECTIONS = 100;
  private static final Logger logger = LogUtil.initializeServerLog(ServerClientThreadPool.class.getName());
}

もちろん、別のプログラムに格納されているクライアントのメイン関数は次のとおりです。

ClientSocketWrapper clientSocketWrapper = ClientSocketWrapper.createSocketWrapperAndConnectTo("localhost", 18000);

/** MAIN ENTRY POINT FOR CLIENT */
while(true) {
  clientSocketWrapper.updateInputOutputStream();
  clientSocketWrapper.writeToOutputStream(executeClientInputProcessing());
  updateGameState(clientSocketWrapper.getServerResponse());
}

これらのメソッドの内部で何が起こっているのかを実際に見ることはできませんが、基本的には Java チュートリアルのようにクライアント側を実装するだけであり、期待どおりに機能します。ここで実行されているメソッドを投稿する必要があると思われる場合はお知らせください。ただし、問題はサーバー側にあると思います。

BONUS QUESTION: ここで正しい軌道に乗っているかどうかも疑問です。ゲームはかなり複雑ですが、Gson を使用してオブジェクトをシリアライズおよびデシリアライズし、送受信される gson 文字列に基づいて適切なアクションを委任するつもりでした。サーバー/クライアント アーキテクチャをグーグルで調べたところ、私のアプローチは単純すぎるようです。より高度なサーバー/クライアント アーキテクチャを学習するための適切なリソースを見つけるのに苦労しているので、優れた書籍やチュートリアルへのリンクがあれば大きな助けになります。

皆さんありがとう!

4

1 に答える 1

3

gameRoom.run()直接電話したくない。run()これにより、現在のスレッドで実行され、そのメソッドが完了するまでサーバー ループが拘束されます。代わりに、別のスレッドで実行する必要があります。Executorsファクトリ クラスから取得したExecutorServiceは、それを処理する簡単な方法です。たとえば、ServerClientThreadPool に ExecutorService を作成します。

public class ServerClientThreadPool {
    private ExecutorService executorService = Executors.newCachedThreadPool();

ソケット接続を受け入れた後、gameRoom をサービスに送信します。

GameRoom gameRoom = new GameRoom(serverListener.accept());
executorService.submit(gameRoom);

extends Thread上記の ServerClientThreadPool について書いていないことに注意してください。上記のコードでは、それをスレッドとして使用していません。また、サーバーが他のことが起こっているときに同時に接続を受け入れる必要がない限り、おそらくそうするのは正しくないでしょう (ゲーム以外に)ルームは、すでに別のスレッドで処理されます)。それが必要な場合は、Runnableではなく でありThread、 にも送信する必要がありExecutorServiceます。

スレッド化の仕組みに関するコードの明らかな混乱に基づいて、Executors に関するセクションを含むJava "Concurrency" tutorialを再確認することをお勧めします。

おまけ: JSON をやり取りすることは、通信の合理的な方法だと思います。そうすることは、パフォーマンスに過度に関心がないことを意味するため、ソケットを自分で処理するのをやめ、代わりにサーバー側で組み込み HTTP サーバーを使用し、クライアント側で単純な HTTP クライアントを使用することをお勧めします。これにより、ソケットとスレッドの無意味な処理がすべて処理され、ゲーム ロジックの詳細について心配する必要がなくなります。

たとえば、Jetty の組み込みは簡単な作業であり、Apache Http ClientJersey REST Clientなど、強力で簡潔な HTTP/REST クライアントが多数あります。

于 2013-02-23T19:05:47.603 に答える