1

Trying to create a rock paper scissors game between two players that is hosted on a local machine using java.net. The problem is that my javafx GUI will not load until both clients are connected. However connecting both clients at once will cause the game to draw and essentially lock.

Here is the client class

import java.io.*;
import java.net.*;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;


public class RPSClient extends Application {
    
    private Button rock, paper, scissors, playAgain;
    private Scene play, displayResult;
    private Text welcomeMessage, rulesMessage, startMessage;
    private static Text resultMessage;
    private static String userSelection;
    private String result;
    
    private static String host = "localhost";
    
    private static Integer port = 100;
    
    
    @Override
    public void start(Stage primaryStage) throws Exception{
        primaryStage.setTitle("Rock-Paper-Scissors");

        // sets the texts for the main scene
        welcomeMessage = new Text("Welcome to Rock Paper Scissors!");
        rulesMessage = new Text("Remember that Rock beats Scissors, Paper beats Rock and Scissors beats Paper.");
        startMessage = new Text("Please make your selection below:");
        resultMessage = new Text(); //result label has not set the string
        
        //Sets up buttons
        rock = new Button( " Rock ");
        paper = new Button( " Paper");
        scissors = new Button(" Scissors ");
        
        //Vbox
        VBox vbox = new VBox();
        vbox.getChildren().addAll(welcomeMessage, rulesMessage, startMessage);
        vbox.setAlignment(Pos.CENTER);
        //Hbox with buttons
        HBox hbox1 = new HBox();
        hbox1.getChildren().addAll(rock, paper, scissors);
        hbox1.setAlignment(Pos.CENTER);
        hbox1.setSpacing(15);
        //new main layout
        VBox main = new VBox(5);
        main.getChildren().addAll(vbox, hbox1);
        main.setAlignment(Pos.CENTER);
        main.setPadding(new Insets(15, 15, 15, 15));
        // sets the containing layout
        BorderPane border = new BorderPane();
        border.setCenter(main);
        
        //details for displayResults scene
        playAgain = new Button("Play Again");
        BorderPane border1 = new BorderPane();
        VBox results = new VBox(10);
        results.getChildren().addAll(resultMessage, playAgain);
        results.setAlignment(Pos.CENTER);
        border1.setCenter(results);
        
        //Sets equal sizes for the scenes
        play = new Scene(border, 600,220);
        displayResult = new Scene(border1, 600,220);
        
        //Actions
        rock.setOnAction( e-> {
            userSelection = "R";
        });
        paper.setOnAction( e -> {
            userSelection = "P";
        });
        scissors.setOnAction( e -> {
            userSelection = "S";
        });
        
        //Sets scene and displays gui
        primaryStage.setScene(play);;
        primaryStage.show();
        
        Socket clientSocket = new Socket(RPSClient.host, RPSClient.port);
        
        DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
        BufferedReader inFromServer = new BufferedReader( new InputStreamReader(clientSocket.getInputStream()));
        String input = userSelection;
        String response;
        
        
        
        //Sent input to server and provide feedback to user
        outToServer.writeBytes(input + "\n");
        resultMessage.setText("\nYour input (" + input + ") was successfully transmitted to the server. Waiting for response");
        
        response = inFromServer.readLine();
        
        //print respones
        System.out.println("Server says: "  + response);
        
    }
    
    

    //GUI ends here

    public static void main(String args[]) throws Exception{

        launch(args);
        
    }
}

and the server class

 * Handles the game logic and controls the game sessions.
 * @author Steven
 *
 */

import java.io.*;
import java.net.*;
import java.util.Scanner;

public class RPSServer {
/**
 * Default port number
 */
    private static Integer port = 1337;
    
    private static Double versionNumber = 1.0;
    
    /** A welcome message :)
     * @var string
     */
    private static String  welcomeMsg = " Rock Paper Scissors V " + versionNumber + "\n";
    
    /**
     * Function takes an integer 'x' and returns the boolean value true
     * if the input is strictly greater than 0 and less that or equal to 65535
     * @param integer
     * @return boolean
     */
    private static boolean validPort(Integer x) {
        return x>= 1 && x <= 65535 ? true: false;
    }
    
    /**
     * Gets the port number from the user or gives the default setting ( Server.port)
     * 
     */
    private static int getPort() {
        Integer input;
        
        Scanner s = new Scanner(System.in);
        
        do {
            System.out.print(("Please selete a port by enetering a number between 1 and 65535"));
            input = s.nextInt();
        } while (input != 0 && !RPSServer.validPort(input));
        s.close();
        
        return input == 0 ? RPSServer.port : input;
    }
    
    public static void main(String args[]) throws Exception {
        
        String resClient_1 = "";
        String resClient_2 = "";
        String inputClient_1;
        String inputClient_2;
        
        System.out.println(RPSServer.welcomeMsg);
        
        //Sets port
        RPSServer.port = RPSServer.getPort();
        
        //Create new server socket
        ServerSocket welcomeSocket = new ServerSocket(RPSServer.port);
        System.out.println("\n Running on port " + welcomeSocket.getLocalPort() + " ...");
        
        while (!welcomeSocket.isClosed()) {

               // Player one
               Socket client_1 = welcomeSocket.accept();
               if (client_1.isConnected()) {
                   System.out.println("\nPlayer one (" + (client_1.getLocalAddress().toString()).substring(1) + ":"
                           + client_1.getLocalPort() + ") has joined ... waiting for player two ...");
               }
               DataOutputStream outClient_1 = new DataOutputStream(client_1.getOutputStream());
               BufferedReader inClient_1 = new BufferedReader(new InputStreamReader(client_1.getInputStream()));

               // Player two
               Socket client_2 = welcomeSocket.accept();
               if (client_2.isConnected()) {
                   System.out.println("Player two (" + (client_2.getLocalAddress().toString()).substring(1) + ":"
                           + client_1.getLocalPort() + ") has joined ... lets start ...");
               }
               DataOutputStream outClient_2 = new DataOutputStream(client_2.getOutputStream());
               BufferedReader inClient_2 = new BufferedReader(new InputStreamReader(client_2.getInputStream()));

               // Get client inputs
               inputClient_1 = inClient_1.readLine();
               inputClient_2 = inClient_2.readLine();

               /**
               * If the characters received from C1 and C2 are the same then the
               * server sends back to both clients the string "DRAW".
               */
               if (inputClient_1.equals(inputClient_2)) {
                   resClient_1 = "Draw";
                   resClient_2 = "Draw";
                   System.out.println("It's a draw.");
               }
               /**
               * If the server receives ’R’ from C1 and ’S’ from C2 it sends the
               * string "YOU WIN" to C1 and the string "YOU LOSE" to C2.
               */
               else if (inputClient_1.equals("R") && inputClient_2.equals("S")) {
                   resClient_1 = "You win";
                   resClient_2 = "You lose";
                   System.out.println("Player one wins.");

               }
               /**
               * If the server receives ’S’ from C1 and ’R’ from C2 it sends the
               * string "YOU LOSE" to C1 and the string "YOU WIN" to C2.
               */
               else if (inputClient_1.equals("S") && inputClient_2.equals("R")) {
                   resClient_1 = "You lose";
                   resClient_2 = "You win";
                   System.out.println("Player two wins.");
               }
               /**
               * If the server receives ’R’ from C1 and ’P’ from C2 it sends the
               * string "YOU LOSE" to C1 and the string "YOU WIN" to C2.
               */
               else if (inputClient_1.equals("R") && inputClient_2.equals("P")) {
                   resClient_1 = "You lose";
                   resClient_2 = "You win";
                   System.out.println("Player two wins.");
               }
               /**
               * If the server receives ’P’ from C1 and ’R’ from C2 it sends the
               * string "YOU WIN" to C1 and the string "YOU LOSE" to C2.
               */
               else if (inputClient_1.equals("P") && inputClient_2.equals("R")) {
                   resClient_1 = "You win";
                   resClient_2 = "You lose";
                   System.out.println("Player one wins.");
               }
               /**
               * If the server receives ’S’ from C1 and ’P’ from C2 it sends the
               * string "YOU WIN" to C1 and the string "YOU LOSE" to C2.
               */
               else if (inputClient_1.equals("S") && inputClient_2.equals("P")) {
                   resClient_1 = "You win";
                   resClient_2 = "You lose";
                   System.out.println("Player one wins.");
               }
               /**
               * If the server receives ’P’ from C1 and ’S’ from C2 it sends the
               * string "YOU LOSE" to C1 and the string "YOU WIN" to C2.
               */
               else if (inputClient_1.equals("P") && inputClient_2.equals("S")) {
                   resClient_1 = "You lose";
                   resClient_2 = "You win";
                   System.out.println("Player two wins.");
               }

               // Send responses in uppercase and close sockets
               outClient_1.writeBytes(resClient_1.toUpperCase());
               outClient_2.writeBytes(resClient_2.toUpperCase());
               client_1.close();
               client_2.close();

               System.out.println("\nWaiting for new players ...\n");

           }    
    }
}
  • 1
    `inFromServer.readLine();` is a blocking call, it will hang the UI thread until a line is read. You can investigate trying some other approach or concurrency in JavaFX. – jewelsea Feb 12 '22 at 21:52
  • 1
    [Example JavaFX app which uses socket communication](https://stackoverflow.com/a/70888362/1155209). – jewelsea Feb 12 '22 at 21:53
  • Ah I see. Where would it make the most sense to move it? – Steven Rojas Feb 12 '22 at 21:59
  • I don't know without spending some time to analyze your application. The example I linked has a couple of alternatives. It provides a synchronous client, but it can only do that because it knows the server is present and will immediately respond and not block when the client reads data. It also provides an asynchronous implementation using a seperate thread for client I/O communication and a JavaFX [Task](https://openjfx.io/javadoc/17/javafx.graphics/javafx/concurrent/Task.html), read the doc. The async implementation was trickier to write and get correct. – jewelsea Feb 12 '22 at 22:05
  • Don't use port `100`. See [Well Known (System) Ports](https://tools.ietf.org/id/draft-cotton-tsvwg-iana-ports-00.html#systemports): "The Well Known Ports are assigned by IANA and cover the range 0-1023. On many systems, they can only be used by system (or root) processes or by programs executed by privileged users.". Best to choose a number [not in this list](https://cyberkmit.github.io/images/List_of_TCP_and_UDP_port_numbers.pdf). – jewelsea Feb 12 '22 at 22:15
  • Huh good to know. Thank you so much! – Steven Rojas Feb 12 '22 at 22:28

0 Answers0