Search code examples
javasocketschatobjectinputstreamjava-threads

Java socket chat application - client ObjectInputStream gets/reads wrong response Object


So, I am trying to make simple java socket chat. Before any chat would be possible, simple login with only a username is required. I send "Message" ("Poruka" in code) objects over ObjectOutputStream, and "Message" objects contain "Sender, Receiver, Content, bool Login, bool Logout".

The sequence is:

  1. Client sends Message (Poruka) with Login set to true and Sender set to username (works fine)
  2. Server Thread successfuly receives the Message, and adds new user to list if similar username doesn't exist in list already (works fine)
  3. Upon receiving information of adding user to the list on server side, Server Thread sends appropriate answer to the Client (here comes the issue).

    The Server Thread code:

       try {
    
        Poruka poruka = null;
        Poruka odgovor = new Poruka();
        while (true) {
            poruka = (Poruka) in.readObject();
             System.out.println("salje prije ifLogin "+poruka.getSalje()+" "+ poruka.isLogin());
            if (poruka.isLogin()) {
                System.out.println("salje "+poruka.getSalje());
                boolean success = Server.dodajKorisnika(poruka.getSalje());
    
                System.out.println("Uspjeh? "+success);
                //System.out.println("Jeste LOGIN poruka "+odgovor.getSadrzaj()+" "+odgovor.isLogout());
                if (success) {
                    System.out.println("USLO  U TRUE BLOK");
                    odgovor.setSadrzaj("ACCEPTED");
                    out.writeObject(odgovor);
               //     out.flush();
                }
                else{
                 odgovor.setSadrzaj("DENIED");
                    out.writeObject(odgovor);
                   // out.flush();
                    System.out.println(odgovor.getSadrzaj()+ " IZ BLOKA NEUSPJEH");
                }
            }
            System.out.println("PORUKA " + poruka.isLogin() + " " + poruka.getSalje());
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    

Here, Server Thread does good job at setting return Message with appropriate login information. If login is successful, Message.Content is set to "ACCEPTED", else it's set to "DENIED". I double checked that.

Now, the problem: Client always receives Message object with "ACCEPTED" for some reason?

Here is the Client Thread code:

  public boolean prijaviSe(String ime) {
    boolean ret = false;
    Poruka prijava = new Poruka();
    prijava.setSalje(ime);
    prijava.setLogin(true);

    try {
        System.out.println("PRIJAVA " + prijava.getSalje());
        out.writeObject(prijava);
        out.flush();
        while (true) {
            Poruka odgovor = (Poruka) in.readObject();
            System.out.println("ODGOVOR "+odgovor.getSadrzaj());
            if (odgovor.getSadrzaj().equals("ACCEPTED")) {
                prijavljen = true;
                  System.out.println("accepted");
                gui.setLabelaPrijavljen("Korisnik uspješno prijavljen");
                break;
            } else if (odgovor.getSadrzaj().equals("DENIED")) {
                prijavljen = false;
                 System.out.println("denied");
                  gui.setLabelaPrijavljen("Promijenite korisničko ime!");
            }
        }//while

    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return ret;
}

I am not sure even what to look for here? Is it a threading issue? Some kind of OutputStream / InputStream conflict? Or is it just my logic? Don't have a clue.


Solution

  • Java serialization is designed to serialize a graph of objects. If an object appears more than once it is only sent once and both references point to the same object. E.g. You can have two objects A and B where each has a reference to each other. But using references and only passing each object once, this all works

    Where this doesn't work as expected is with mutable objects. If you pass an object more than once you get a reference to the same object. It does/can't check whether you changed it.

    Note this means you are retaining every object ever written or read which can be a subtle memory leak.

    The solution is to call reset() which clears the cached objects and sends any object again including updates.