I wanted to create a simple game with a server and more than one clients. Server will have several Hashmaps and Arraylists. Server will broadcast these to clients, then one by one a client may modify these and send back to server and then server will broadcast updated values to all clients.
To get started, I have created Server - Client chat app. When a client sends String message to server, Server will add that String message to it's Arraylist and will broadcast that arraylist to all clients. I have used threads so that multiple clients can send messages concurrently, but I haven't applied thread-safety yet.
Lets come to the problem. for the first time when a client sends String to server, server prints it well, add to it's arraylist, then broadcasts it to all clients and all clients can see that too. But next time when client sends String message, server accepts it, adds to arraylist and broadcasts it, but this time all clients gets old arraylist ( list with only one String which was added first ). I have printed arraylist before broadcasting and it shows modified values, but at client side it shows list with one entry only.
Part of Server code
public class ServerGUI extends javax.swing.JFrame { public static final int SERVER_PORT = 4000; private ServerSocket ss; ArrayList<String> al; ArrayList<ClientHandler> clients; public ServerGUI() { initComponents(); setVisible(true); al = new ArrayList<>(); clients = new ArrayList<>(); initNet(); } private void initNet() { Socket ds = null; try { ss = new ServerSocket(SERVER_PORT, 1); while (true) { ds = ss.accept(); clients.add(new ClientHandler(ds)); } } catch (Exception e) { System.out.println("shutting down server......"); } } class ClientHandler extends Thread { private Socket ds; private ObjectOutputStream out; private ObjectInputStream in; public ClientHandler(Socket ds) throws Exception { this.ds = ds; out = new ObjectOutputStream(ds.getOutputStream()); in = new ObjectInputStream(ds.getInputStream()); start(); } public ObjectOutputStream getOut() { return out; } public void run() { try { while (true) { acceptData(in); broadcastData(); } } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("Finally called. socket closed"); if (ds != null) { try { ds.close(); } catch (IOException e) { e.printStackTrace(); } } } } } private void acceptData(ObjectInputStream in) throws Exception { System.out.println("acceptData called by " + Thread.currentThread().getName()); String s = (String) in.readObject(); al.add(s); jta.setText(al.toString()); } private void broadcastData() throws Exception { System.out.println("broadcast called by " + Thread.currentThread().getName()); System.out.println("al is : \n" + al); for (ClientHandler clnt : clients) { clnt.getOut().writeObject(al); clnt.getOut().flush(); } }
Part of Client code
public class ClientGUI extends javax.swing.JFrame { public static final int SERVER_PORT = 4000; public static final String SERVER_IP = "127.0.0.1"; private Socket s1; private ObjectOutputStream out; private ObjectInputStream in; private ArrayList<String> al; public ClientGUI() { initComponents(); setVisible(true); initNet(); } private void initNet() { try { s1 = new Socket(SERVER_IP, SERVER_PORT); out = new ObjectOutputStream(s1.getOutputStream()); in = new ObjectInputStream(s1.getInputStream()); System.out.println("connected to server"); new ReadData(); } catch (Exception e) { e.printStackTrace(); } } class ReadData extends Thread { public ReadData() { start(); } public void run() { System.out.println("client thread started"); try { while (true) { al = (ArrayList<String>) in.readObject(); System.out.println("client read completed, al is "+al); jta.setText(al.toString()); } } catch (Exception e) { e.printStackTrace(); } } } private void textFieldActionPerformed(java.awt.event.ActionEvent evt) { try { out.writeObject(jtf.getText()); out.flush(); } catch (Exception e) { e.printStackTrace(); } }
I have attached netbeans projects if you want to try.