Skip to content

Server doesn’t forward message to all in the chat

i am trying to create a simple chat app using java sockets, the server is threaded, when a client connects its socket is added to an ArrayList, so that i can send to all in that list.

the problem is when 3 clients are connected, the for loop that sends doesn’t work properly, for ex : client 0 sends to both 1 and 2 but client 2 doesn’t send to anyone 🙁

The server and the ClientHandler :

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

public class MainServer {

    private static int portnumber = 6968;
    static ArrayList <ClientHandler> allClients = new ArrayList<>();

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

        // init
        // server works by default on localhost
        ServerSocket serversocket = new ServerSocket(portnumber);
        int clientNo = 0;
    
        System.out.println("server is running on port : " + portnumber);

        while (true) {

          // creating a socket for each connection
          Socket clientsocket = null;

          try {
             // receiving incoming requests from users/clients
            clientsocket = serversocket.accept();

            // input and output from client
            PrintWriter out = new PrintWriter(clientsocket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(clientsocket.getInputStream()));

            // create a threads
            ClientHandler ch = new ClientHandler(clientsocket, "Client#" + clientNo, in, out);
        
            // adding to the clientList
            allClients.add(ch);

            System.out.println(ch.clientName + " has joined");
            Thread clientThread = new Thread(ch);
            
            clientThread.start();

            // decrease when user leaves
            clientNo++;
           
          } catch (Exception e) {
            clientsocket.close();
            e.printStackTrace();
            System.exit(1);

            //out.close();
            //in.close();
            //clientSocket.close();
            //serverSocket.close();
          }
        }
    }
}


// handle client requests
public class ClientHandler implements Runnable{

  public String clientName;
  public Socket clientsocket = null;
  public boolean active = false;
  private BufferedReader inp;
  private PrintWriter out;
  private final String EXIT_STR = "exit";
  public Scanner clientSc = new Scanner(System.in);

  public ClientHandler(Socket socket, String name, BufferedReader inp, PrintWriter out) {
    this.clientsocket = socket;
    this.clientName = name;
    this.inp = inp;
    this.out = out;

    // active when the thread is created
    this.active = true;
  }

  @Override
  public void run() {

    // getting the output temp
    String recivedMsg = "";
    
    while (true) {
      try {
        recivedMsg = inp.readLine();

        System.out.println(recivedMsg);

        // check for ctrl+C
        if (recivedMsg.equals(this.EXIT_STR)){

          // send to all
          System.out.println(this.clientName + " exits");

          // close the connection and break
          this.active = false;
          this.clientsocket.close();

          // bye
          break;
        }

        // send to all except me
        for (ClientHandler client : MainServer.allClients){

          if (!client.clientName.equals(this.clientName)){
            client.out.println(this.clientName + ":" + recivedMsg);
            client.out.flush();
            break;
          }
        }
        
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    try {
      // clean
      this.clientsocket.close();
      this.inp.close();
      this.out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

The client :

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client {
  private String hostName; 
  private int portNumber;

  // set connction and server
  public PrintWriter out = null;
  public BufferedReader in = null; 
  public Socket clientSocket = null;

  Client(String hostName, int port) {
    this.hostName = hostName;
    this.portNumber = port;

    // setting the connction
    this.setConnection();
  }

  private void setConnection () {

    try {
      this.clientSocket = new Socket(this.hostName, this.portNumber);
      this.out = new PrintWriter(this.clientSocket.getOutputStream(), true);
      this.in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
    }

 }

  public void sendMessageToServer(String msg) {
    //System.out.println("The msg is : " + msg);
    out.println(msg);
  }

  public String readMessage() {
    String outputMsg = "";
    try {
      outputMsg =  in.readLine();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return outputMsg;
  }


  // shit cleaning
  public void closeSession(){

    try {
      this.out.close();
      this.in.close();
      this.clientSocket.close();
    } catch (IOException e) {
      e.printStackTrace();
      System.exit(1);
    }
    System.out.println("Session has been terminated!");
  }

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

    // init    
    String host = "localhost";
    int port = 6968;

    Client newClient = new Client(host, port);

    // // send a message 
    Scanner sc = new Scanner(System.in);

    Thread sendMsg = new Thread(new Runnable() {

      @Override
      public void run() {
        while (true) {

          try {

            String userInput = sc.nextLine();
            newClient.sendMessageToServer(userInput);

            if (userInput.equals("exit")) {
              System.exit(1);
            }
          } catch (Exception e) {
            System.exit(1);
          }
        }
      }
    });

    Thread getMsg = new Thread(new Runnable() {

      @Override
      public void run() {
        while (true) {

          String msgRead = "";

          try {

            msgRead = newClient.readMessage();

            System.out.println(msgRead);

          } catch (Exception e) {
            System.exit(1);
          }
        }
      }
    });


    sendMsg.start();
    getMsg.start();
  }
}

I think the problem is here :

        // send to all except me
        for (ClientHandler client : MainServer.allClients){

          if (!client.clientName.equals(this.clientName)){
            client.out.println(this.clientName + ":" + recivedMsg);
            client.out.flush();
            break;
          }
        }

Answer

The fix is straightforward: remove the break statement from the loop where you think the problem is.

This break statement causes the loop through all the ClientHandlers to stop as soon as it sends the message to one client. You don’t want this: you want this loop to keep going and send the message to all clients other than the one that wrote the message.