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; } }
Advertisement
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 ClientHandler
s 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.