Link to home
Start Free TrialLog in
Avatar of Simon Leung
Simon Leung

asked on

Multi client server Java program

I have written a client server programming. Currently, I find that it only allows two clients to go into the critical section (the synchronized code). If a third client is started, it can only go into the section if one the the client quit. I try to debug whole day but can't fix out what's wrong. Any idea or advise ?

Thx
Server

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;


public class Server {
public static void main(String args[]){

   int PlayerIdx = 0;

    Socket s=null;
    ServerSocket ss2=null;
    System.out.println("Server Listening......");
    try{
        ss2 = new ServerSocket(4445); // can also use static final PORT_NUM , when defined

    }
   catch(IOException e){
    e.printStackTrace();
    System.out.println("Server error");

    }

   GameWinner game = new GameWinner(false);
   
    while(true){
      try{
            s= ss2.accept();
            System.out.println("connection Established");
            ServerThread st=new ServerThread(s, PlayerIdx, game);  //start new thread for any incoming connection
            PlayerIdx++;
            st.start();

      }
      catch(Exception e){
            e.printStackTrace();
            System.out.println("Connection Error");

      }
    }

}

}

class GameWinner {
   boolean gameover;
   
   GameWinner(boolean bover)
   {
      this.gameover = bover;
   }
    
   boolean GetWinner(){
      return gameover;
   }
   
   void SetWinner(boolean bover){
      this.gameover = bover;
   }
}

class ServerThread extends Thread{  

    String line=null;
    BufferedReader  is = null;
    PrintWriter os=null;
    Socket s=null;
   
   int PlayerID;
   boolean neverPlay= true;
   GameWinner GamePlay;


    public ServerThread(Socket s, int p, GameWinner g){
        this.s=s;
      this.PlayerID=p;
      this.GamePlay=g;

    }

  public void run() {
    try{
        is= new BufferedReader(new InputStreamReader(s.getInputStream()));
        os=new PrintWriter(s.getOutputStream());

    }catch(IOException e){
        System.out.println("IO error in server thread");
    }
   try {
      
        line = "";
      
      while (line.compareTo("QUIT")!=0)  {
         
         //Sync Start
         synchronized(GamePlay) {
            if ((neverPlay == false)  ) {
               try {            
                  GamePlay.wait();  //wait for execution
                                    
               }catch(InterruptedException e){
                  e.printStackTrace();
               }
            }
            
            
            if (!GamePlay.GetWinner()) {
               try{
                  os.println(PlayerID + ", your turn now" );  // send message to client
                  os.flush();  //forces any buffered output bytes to be written out to their intended destination
            
                  line=is.readLine();         
                  System.out.println("Client Input :  " + line);

                  System.out.println("Game Start");
                  Thread.currentThread().sleep(5000);
                  System.out.println("Game End");
                }
               catch (InterruptedException itro){
                   System.out.println("sleep is interrupted");
               }   
            }
            
            if (line.compareTo("OK")==0) {
               line = "";
               GamePlay.SetWinner(true);
               System.out.println(PlayerID + " win the game.");
               os.println("UWIN" );  // send message to client
               os.flush();  //forces any buffered output bytes to be written out to their intended destination
            }else if (GamePlay.GetWinner()) {
               os.println("QUIT");   //send to the server
               os.flush();
            } 
            neverPlay=false;
            GamePlay.notify();  //notify execution
   
         }  //Sync End
               
        }   
    } catch (IOException e) {

        line=this.getName(); //reused String line for getting thread name
        System.out.println("IO Error/ Client "+line+" terminated abruptly");
    }
    catch(NullPointerException e){
        line=this.getName(); //reused String line for getting thread name
        System.out.println("Client "+line+" Closed");
    }
finally{    
    try{
        System.out.println("Connection Closing..");
        if (is!=null){
            is.close(); 
            System.out.println(" Socket Input Stream Closed");
        }

        if(os!=null){
            os.close();
            System.out.println("Socket Out Closed");
        }
        if (s!=null){
        s.close();
        System.out.println("Socket Closed");
        }
    }
    catch(IOException ie){
        System.out.println("Socket Close Error");
    }
    }//end finally
    }
}


Open in new window


Cient
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

public class Client {

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


    InetAddress address=InetAddress.getLocalHost();
    Socket s1=null;
   BufferedReader is=null;
   
    String line=null;
    BufferedReader br=null;
    
    PrintWriter os=null;   
   
   try {
        s1=new Socket(address, 4445);  
        
      //get server response, read from BufferedReader, console input
      br= new BufferedReader(new InputStreamReader(System.in));
      
      //get socket's input stream and open BufferedReader
        is=new BufferedReader(new InputStreamReader(s1.getInputStream()));
        
      //get sockets output stream and opens a PrinterWriter
      //(send data through socket to server and write to PrinterWriter
      os= new PrintWriter(s1.getOutputStream()); 
    }
    catch (IOException e){
        e.printStackTrace();
        System.err.print("IO Exception");
    }
   System.out.println("Client Address : "+address);
    System.out.println("Enter Data to echo Server ( Enter QUIT to end):");

    String response=null;
    try{
         line = "";
        while(line.compareTo("QUIT")!=0){
         
         response=is.readLine();   //read a line of information from BufferedReader connected to the socket
            System.out.println("Server Response : "+response);
         
         if (response.compareTo("UWIN")==0) {
               System.out.println("You win the game ! " );
         }
         
         if ((response.compareTo("QUIT")!=0) && (response.compareTo("UWIN")!=0)){
            line=br.readLine();
            os.println(line);   //send to the server
            os.flush();
         } else {
            line = "QUIT";
            os.println("QUIT");   //send to the server
            os.flush();
            break;
         }
        }
    }
    catch(IOException e){
        e.printStackTrace();
    System.out.println("Socket read Error");
    }
    finally{

        br.close();os.close();br.close();s1.close();
                System.out.println("Connection Closed");

    }

}
}

Open in new window

Avatar of ste5an
ste5an
Flag of Germany image

Start by sketching out (and explaining) the game type and logic. When needs a new game to be established and how are players assigned to it?

The communication needs to reflect that. Thus you need communication for connecting, requesting to participate at a new game, and the actual game communication.

This means that you need to communicate between your threads. First with the "tournament managment" who coordinates when new games are started and when players are assigned to games, basically a kind of scheduler And then the "game director" which handles the actual game and the associated communication.

E.g. something like

import java.io.*;
import java.net.*;

public class GameServer {
    public static void main(String[] args) {
        int port = 4445;
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            Tournament tournament = new Tournament();
            System.out.println("Server is listening on port " + port);
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("New client connected");
                new GameServerThread(socket, tournament).start();
            }
        } catch (IOException ex) {
            System.out.println("Server exception: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
}

public class GameServerThread extends Thread {
    private Game game;
    private Socket player;
    private Tournament tournament;

    public GameServerThread(Socket player, Tournament tournament) {
        this.player = player;
        this.tournament = tournament;
    }

    public void run() {
        try {
            InputStream input = player.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            OutputStream output = player.getOutputStream();
            String command;
            do {
                command = reader.readLine();
                if (this.game == null) {
                    game = tournament.execute(player, command);
                } else {
                    game.execute(player, command);
                }

            } while (!command.equals("QUIT"));

            // Call game clean-up before closing socket.
            player.close();
        } catch (IOException ex) {
            System.out.println("Server exception: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
}

public class Tournament {
    public Game execute(Socket player, String command) {
        Game game;
        // register waiting players and start a new game if possible.
        return game:
    }
}

public class Game {
    private Tournament tournament;

    public Game(List<Socket> players, Tournament tournament) {
        // Store players and initialize game.
        this.tournament = tournament;
    }

    public void execute(Socket player, String command) {
        // Handle the in-game commands.
    }
}

Open in new window

The game and tournament class should be derived from a base class, which implements the state machine which does the command text parsing.
I find that it only allows two clients to go into the critical section (the synchronized code). 

Please point me to the synchronized section of your code, I can't spot it.
Avatar of Simon Leung
Simon Leung

ASKER

Server :Line 100: synchronized(GamePlay) { 
OK, I'll take a look. But a good idea to start along the more structured approach that ste5fan is outlining.
The structured outlined by ste5fan is excellent but this is not the requirement that I want. Basically, multiclient can access the application at any time. Every client will take turn to access a synchronized code. If any one win the game will announcement the result and stop the whole application. Hence, I need to implement a synchronized code to ensure only one thread can execute at any time, but each thread get equal chance to access the code.

Thx
Well then the principle to follow then is the same as the one I’ve provided in your other question - Mary and co. all have an equal chance at the pool.
ASKER CERTIFIED SOLUTION
Avatar of ste5an
ste5an
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial