views:

71

answers:

3

hi. im trying to create a client server game using java sockets. i have a thread server which controls the logic of the game. i also have client threads that communicate with the server. i use multiple client handler threads to facilitate server to client communication. i use multiple threads to communicate with other client threads using sockets.

now, i have a problem on how to facilitate communication between the server thread and the multiple client threads. For example, should the server select the next player to play, how should it signal the client handler thread, and in turn communicate with the client thread through sockets?

A: 

I suspect that your client threads are hanging on a blocking read operation. To "release" these threads and make them send data instead, you'd have to interrupt them through thread.interrupt(). (Which would cause the blocking read to throw an InterruptedException.)

However, I've written a few network games myself, and I would really recommend you to look into the java.nio packages and especially the Selector class. Using this class you could easily make the whole server single-threaded. This would save you a lot of headaches when it comes to synchronizing all those client threads.

aioobe
A: 

I think using an existing communication infrastructure like ActiveMQ would be very useful here to deal with the low-level piping stuff and allow you to tackle the game design issues at a higher conceptual level rather than dealing with the low-level intricacies.

That being said. If I understood you then you have a game-client with mutiple threads, one of which deals with comms to the server. On the server there is a comms thread for each client and the game server logic.

I would only use sockets for remote communication and Queues for communication between the server threads. On the queues send immutable objects (or copies) back and forth so you do not need to synchronize access to the data in the messages. As a base for synchronisation you can block on the Socket or a BlockingQueue, then you do not need to manually synch things, however this requires careful protocol design.

Peter Tillemans
+1  A: 

I have done this before in the following way. I have a Server socket

    public Server(int port, int numPlayers) {
    game = new PRGameController(numPlayers);

    try {

        MessageOutput.info("Opening port on " + port);
        ServerSocket clientConnectorSocket = new ServerSocket(port);
        MessageOutput.info("Listening for connections");

        while (!game.isFull()) {
            // block until we get a connection from a client
            final Socket client = clientConnectorSocket.accept();
            MessageOutput.info("Client connected from " + client.getInetAddress());

            Runnable runnable = new Runnable() {
                public synchronized void run() {
                    PRGamePlayer player = new PRGamePlayer(client, game);
                }
            };
            new Thread(runnable).start();
        }
    } catch (IOException io) {
        MessageOutput.error("Server Connection Manager Failed...Shutting Down...", io);
        // if the connection manager fails we want to closedown the server
        System.exit(0);
    }
}

Then on the client side, I have something like this..

public void connect(String ip) {

        try {
            comms = new Socket(ip, 12345);
            comms.setTcpNoDelay(true);
             // get the streams from the socket and wrap them round a ZIP Stream
            // then wrap them around a reader and writer, as we are writing strings
             this.input =  new CompressedInputStream(comms.getInputStream());
             this.output = new CompressedOutputStream(comms.getOutputStream());
             this.connected = true;
             startServerResponseThread();

        } catch (IOException e) {
            ui.displayMessage("Unable to connect to server, please check and try again");
            this.connected = false;
        }

        if (connected) {
            String name = ui.getUserInput("Please choose a player name");
            sendXML(XMLUtil.getXML(new NameSetAction(name, Server.VERSION)));
        }
    }

    /**
    * This method sets up the server response thread. The thread, sits patiently
    * waiting for input from the server, in a seperate thread, so not to hold
    * up any client side activities. When data is recieved from the server
    * it is processed, to perform the appropriate action.
    */
   public void startServerResponseThread() {

      // create the runnable that will be used by the serverListenerThread,
      // to listen for requests from the server
      Runnable runnable = new Runnable() {

         public void run () {

            try {
               // loop forever, or until the server closes the connection
               while (true) {

                  processRequest(input.readCompressedString());
               }
            } catch (SocketException sx) {
               MessageOutput.error("Socket closed, user has shutdown the connection, or network has failed");
            } catch (IOException ex) {
               MessageOutput.error(ex.getMessage(), ex);
            } catch (Exception ex) {
               MessageOutput.error(ex.getMessage(), ex);
            } finally {
               (PRClone.this).connected = false;
               // only shutdown the server if the listener thread has not already been
               // destroyed, otherwise the server will have already been shutdown
               if (serverListenerThread != null) {
                  // shutdown the thread and inform the application the communications has closed
                  MessageOutput.debug("Shutting down server listener Thread");
               }
            }
         }
      };

      // create the thread
      serverListenerThread = new Thread(runnable);
      // start the thread
      serverListenerThread.start();

   }

The the client is able to send requests to the server via the outputstream, and read server data from the input stream.

The server can accept requests from the client, and process it in the GameController, and can also send notifications from the server using outputstream, again in the GameController.

EDIT: Also, I should note that all my communication is done via XML, and the controller on the client or the server decodes the XML and performs the relevant request.

Hope this helps. It certainly does the job for me, and allows my multi-player games to work well.

Codemwnci
I do almost exactly the same thing! :-)
Jonathan