0

I've been trying to make the code below to have multiple clients communicate with the same server. Currently, it works one client at a time with the server but it seems to be that when the second client opens, code stops at new ObjectInputStream(connection.getInputStream()); in the Class 3 (client) - see below.

I've tried making the inputstream object transient to be shared in different threads but it didn't work, nor with making runClient method synchronized.

If I were to implement Serializable in the client class using serialVersionUID, how can I make multithreading work with the same server or is there any better way..?

Class 1 - server main

public class EchoServer {

private ServerSocket server;
private int portNum;
public static final int DEFAULT_PORT = 8081;

public EchoServer(int portNum) {
    this.portNum = portNum;
} 

public void runServer() {
    System.out.println("Echo Server started...");

    try {
        server = new ServerSocket(portNum);
        Socket connection = server.accept();
        new Thread(new ClientHandler(connection)).run();
    } catch(IOException ex) {
        System.err.println("Error encountered! Port is likely already in use! Exiting program...");
        ex.printStackTrace();
    }
}

public static void main(String[] args) {
    if (args.length > 0) {
        (new EchoServer(Integer.parseInt(args[0]))).runServer();

    } else {
        (new EchoServer(DEFAULT_PORT)).runServer(); 
    }
  } 
}

Class 2

public class ClientHandler implements Runnable {

private ObjectOutputStream output;
private ObjectInputStream input;
private String message;

/** Integer to hold the message number. */
private int messagenum;
private Socket connection;

public ClientHandler(Socket connection) {
    this.connection = connection;
}

@Override
public void run() {
    do{
        handleRequest();
    } while (true);
}

public void handleRequest() {
    try {
        output = new ObjectOutputStream(this.connection.getOutputStream());
        input = new ObjectInputStream(this.connection.getInputStream());
        do { 
            try {
                message = (String) input.readObject();
                System.out.println(messagenum +" Output> " +message);
            } catch (EOFException | SocketException e) {
                message = null;
            }

            if (message != null) {
                output.writeObject(messagenum +" FromServer> " +message);
                output.flush();
                ++messagenum;
            }
        } while (message != null);
        input.close();
        output.close();
        this.connection.close();

    }  catch (IOException | ClassNotFoundException ex) {
        System.err.println("Error encountered! Exiting program...");
        ex.printStackTrace();           
    }
  }
}

Class 3 - client main

public class EchoClient implements Serializable {
   private static final long serialVersionUID = 1L;
   private Socket connection;
   private ObjectOutputStream output;
   private transient ObjectInputStream input;
   private String message = "";
   private static String serverName;
   public static final String DEFAULT_SERVER_NAME = "localhost";
   private static int portNum;
   BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));

public EchoClient(String serverName, int portNum) {
    this.serverName = serverName;
    this.portNum = portNum;
}


public synchronized void runClient() {
    try {           
        connection = new Socket(InetAddress.getByName(serverName), portNum);
        output = new ObjectOutputStream(connection.getOutputStream());
        input = new ObjectInputStream(connection.getInputStream());

        do {
            System.out.print("Input> ");
            message = keyboard.readLine();

            if (message != null){
                output.writeObject(message);    
                output.flush();
                message = (String) input.readObject();
                System.out.println(message);
            }
        } while (message != null);
        input.close();
        output.close();
        connection.close();
    } catch (IOException ioException) {
        ioException.printStackTrace();
    } catch (ClassNotFoundException exception) {
        exception.printStackTrace();
    }
} 


public static void main(String[] args) {
    switch (args.length) {
    case 2:
        (new EchoClient(args[0], Integer.parseInt(args[1]))).runClient();
        break;
    case 1:
        (new EchoClient(DEFAULT_SERVER_NAME, Integer.parseInt(args[0]))).runClient();
        break;
    default:
        (new EchoClient(DEFAULT_SERVER_NAME, server.EchoServer.DEFAULT_PORT)).runClient();
    }
  } 
} 
0

3 Answers 3

1

Call server.accept() in the loop to accept multiple client connections as mentioned in the other answers. Start a new thread with the Thread.start method instead of Thread.run- What's the difference between Thread start() and Runnable run().

volatile boolean isRunning = true;
public void runServer() {
    System.out.println("Echo Server started...");

    try {
        server = new ServerSocket(portNum);
        while(isRunning) {
           Socket connection = server.accept();
           new Thread(new ClientHandler(connection)).start();
        }
    } catch(IOException ex) {
        System.err.println("Error encountered! Port is likely already in use! Exiting program...");
        ex.printStackTrace();
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

When I added a loop with a regular boolean, it didn't work until I added volatile.! volatile was the key point in this case i guess. Thank you bunch!
oh actually calling start method instead of run method made a big difference! I will study the link you provided. :)
1

run server needs to wait for connections in a loop otherwise it will connect once and that is it. It needs to close its connections too. Clean up its threads. that's just in server main. I'm pretty sure this is a duplicate. So keep on researching

Comments

1

As said by efekctive, you need your server.accept() in a loop, else it will accept the first client and exit the program. So put these two lines in runServer() in a loop like this:

boolean isRunning = true;
while(isRunning){
    Socket connection = server.accept();
    new Thread(new ClientHandler(connection)).run();
}

1 Comment

Thanks for your help but it didn't work with your example. I added volatile as Alexdander mentioned above and it worked!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.