I'm writing a server/client chat application in Java. In order to receive messages and then print the total dialog of the conversation, I add each message from the client to an ArrayList of Strings, and then send the whole ArrayList back to the client, to print out as the entire conversation.
My problem is that even though I am constantly adding elements to the ArrayList in the server, whenever I send it to the client, the size does not change, and only the first element is stored.
Server Program:
public class ArrayListServer {
public static void main(String[] args) {
int port = 8000;
String me = "Server: ";
ArrayList<String> convo = new ArrayList<String>();
try {
ServerSocket server = new ServerSocket(port);
System.out.println("Waiting for connection...");
Socket client = server.accept();
System.out.println("Established connection.");
ObjectInputStream in = new ObjectInputStream(client.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
int i = 0;
// receive messages from client
while (true) {
String msgFromClient = (String)in.readObject();
convo.add(msgFromClient);
System.out.println(me + "size: " + convo.size());
out.writeObject(convo);
}
} catch (IOException ioex) {
System.out.println("IOException occurred.");
} catch (ClassNotFoundException cnfex) {
System.out.println("ClassNotFoundException occurred.");
}
}
}
Client Program:
public class ArrayListClient {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
int port = 8000;
String me = "Client: ";
Scanner input = new Scanner(System.in);
ArrayList<String> convo = new ArrayList<String>();
try {
Socket client = new Socket("localhost", port);
ObjectOutputStream toServer = new ObjectOutputStream(client.getOutputStream());
ObjectInputStream fromServer = new ObjectInputStream(client.getInputStream());
while (true) {
System.out.print("> ");
String msg = input.nextLine().trim();
toServer.writeObject(msg);
convo = (ArrayList<String>)fromServer.readObject();
System.out.println(me + "size: " + convo.size());
}
} catch (UnknownHostException uhex) {
System.out.println("UnknownHostException occurred.");
} catch (IOException ioex) {
System.out.println("IOException occurred.");
} catch (ClassNotFoundException cnfex) {
System.out.println("ClassNotFoundException occurred.");
}
}
}
When I run the server and client, my output is:
> hi
Client: size: 1
> hi
Client: size: 1
> hi
Client: size: 1
> hi
Client: size: 1
> hi
Client: size: 1
> hi
Client: size: 1
>
Server: Waiting for connection...
Server: Established connection.
Server: size: 1
Server: size: 2
Server: size: 3
Server: size: 4
Server: size: 5
Server: size: 6
I know the ArrayList<> and String class are both serializable, so I have no clue why this isn't working. I think it may be something to do with my Input/Output streams, but when I declared them local to the while loop and closed them at the end of it, my program would throw an IOException and halt.
What am I doing wrong?
I solved it. You use the same ObjectOutput and ObjectInput instances. ObjectOutput tries to not rewrite instances it has seen before. So the first time the server writes the convo array list it keeps a reference to it. When you add to it the reference does not change even though the contents of the list do. If you make the one line change below in your server this will prove to you that this is the problem:
out.writeObject( new ArrayList( convo ) );
The above is not a great solution because the ObjectOutputStream's reference map will keep growing one very iteration. But it will show you what the problem is so you can create a better solution.
The better solution is to just move the getInputStream and getOutputStream lines within the loop on both sides.
Also in case it's not obvious the strings work because on each iteration they are a different object reference. The List does not because on the server side you write the same reference each time even though it changes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With