服务器线程无法看到序列化对象的已更改字段

时间:2013-03-27 18:59:05

标签: java sockets serialization objectoutputstream objectinputstream

我面临着通过TCP套接字发送和接收序列化对象的问题。实际上,我可以在服务器线程和客户端线程之间正确地接收/发送对象。但是,问题是如果更改了接收/发送对象的属性值,则等待线程无法实现此更改。请考虑此代码示例;

public class ClientThread extends javax.swing.JFrame implements Runnable {

ClientObject mainClient; // Initiliazed after sockets connect to server successfully
.
.
.
      String addNewBuddy = JOptionPane.showInputDialog(this, "Enter the Username of the person who you want to add...");

      mainClient.setBuddyRequest(true);
      mainClient.setBuddyRequestAccount(addNewBuddy);

      send.writeObject(mainClient); // write into an ObjectOutputStream
      send.flush(); // flush it

      System.out.println("mainClient.setBuddyRequest : " + mainClient.isBuddyRequest() + " setBuddyRequestAccount : " + mainClient.getBuddyRequestAccount()); // Check if values changed properly

      ClientObject tempClientObject; // temporary an instance of ClientObject

      while(( tempClientObject = (ClientObject) receive.readObject()) != null){

           if( !tempClientObject.isBuddyRequest() ){

                    JOptionPane.showMessageDialog(this, "Buddy Request Information", "Requested buddy doesnt exist!!!", JOptionPane.ERROR_MESSAGE);
                    break;
                }

                else{
                    JOptionPane.showMessageDialog(this, "Buddy Request Information", "Requested buddy added into your buddy list succesfully", JOptionPane.INFORMATION_MESSAGE);
                    labelSetText = tempClientObject.getNickName();
                    onlineStatus = tempClientObject.isIsOnline();
                    model.addElement(createPanel());
                }

            }
.
.
.
}

所以在我改变mainClient的一些属性后,我将它发送到服务器。这是服务器线程等待对象给出一些反应的部分。此外,当客户端发送第二个对象(使计数器大于0)时,服务器线程可以无错误地读取它,但我发现即使客户端将修改后的对象作为第二个消息发送到服务器,第一个和第二个对象的属性之间也没有差异!

        while( ( clientO = (ClientObject) receive.readObject()) != null ){

                counterMessage++;

                 if( counterMessage==1) { // 

                     checkAccountIfExist(toWrite,file.exists(),toModify,clientO); // Check is connected account exist in database of server

                 } // end of if (counter==1)

                 else{ // Second time when server waits 

// prints counter=2 but clientO.isBuddyRequest printed as 'false' 
//instead of 'true' so this makes if statement unreachable!
                     System.out.println("Counter = " + counterMessage + "  BUDDYREQUEST : " + clientO.isBuddyRequest() + " USERNAME : " + clientO.getUserName());

                     if(clientO.isBuddyRequest()){
                         System.out.println("Entered");
                         checkBuddyAvalaible(clientO);
                     }

                 }

        }

最后是我的序列化ClientObject的代码

public class ClientObject implements Serializable {

    private static final long serialVersionUID = 8662836292460365873L;
    private String userName;
    private String password;
    private String nickName;
    private String message;
    private boolean checkAcc;
    private LinkedList<ClientObject> buddyList;
    private boolean isOnline;
    private boolean buddyRequest;
    private String buddyRequestAccount;

    public ClientObject(String userName, String password){

        this.userName = userName;
        this.password = password;
        this.checkAcc = false;
        this.buddyList = new LinkedList<ClientObject>();
        this.isOnline = false;
        this.buddyRequest = false;
        this.buddyRequestAccount = null;
    }

   ...methods of getters and setters
}

我希望我已经明确了这个问题,我会对每一个答案都表示赞赏,不管怎样,谢谢。

2 个答案:

答案 0 :(得分:3)

您需要做的就是调用ObjectOutputStream.reset(),或者使用writeUnshared()。

答案 1 :(得分:1)

我猜你正在写发送代码:

.....
mainClient = new ClientObject(userName, password);
String clientNickName = JOptionPane.showInputDialog(this, "Enter your NickName");
mainClient.setNickName(clientNickName);
send.writeObject(mainClient);
send.flush();
......

在一个循环中。如果是这样,你应该阅读关于java序列化的这个事实:

  

在执行对象的序列化时,Java形成数据结构   类似于对象图,以确定需要哪些对象   序列化。它从主要对象开始序列化,并且   递归遍历从主对象可到达的所有对象。   对于它遇到的每个对象,需要序列化,它   关联标记该对象的标识符   序列化到给定的ObjectOutputStream实例。所以当Java   遇到已标记为序列化的同一对象   到ObjectOutputStream,它不会再次序列化对象,   而是序列化同一对象的句柄。这就是Java   避免必须重新序列化已经序列化的对象。


编辑
根据 EJP的评论,我更新了帖子,向OP提供了正确的信息。
第一次通过ClientObjectOutputStream发送ObjectOutputStream对象后,下次发送ClientObject的更改对象时,java会检查此类对象是否为已被序列化。由于它已经被序列化,所以java不会序列化再次创建的新object。这就是为什么你在另一边得到同样的对象。
对此问题的回忆是,每次您要发送ClientObject的已更改对象时,请重置ObjectOutputStream,如:

send.reset();  

然后将更改的对象发送到另一端。