Java 服务器线程无法看到序列化对象的已更改字段
我面临通过TCP套接字发送和接收序列化对象的问题。实际上,我可以在服务器线程和客户端线程之间正确地接收/发送对象。但是,问题是,如果更改了接收/发送对象的属性值,则等待的线程无法实现此更改。考虑这个代码示例;Java 服务器线程无法看到序列化对象的已更改字段,java,sockets,serialization,objectoutputstream,objectinputstream,Java,Sockets,Serialization,Objectoutputstream,Objectinputstream,我面临通过TCP套接字发送和接收序列化对象的问题。实际上,我可以在服务器线程和客户端线程之间正确地接收/发送对象。但是,问题是,如果更改了接收/发送对象的属性值,则等待的线程无法实现此更改。考虑这个代码示例; public class ClientThread extends javax.swing.JFrame implements Runnable { ClientObject mainClient; // Initiliazed after sockets connect to serv
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);
}
}
}
最后是我的SerializeLible 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
}
公共类ClientObject实现可序列化{
私有静态最终长serialVersionUID=8662836292460365873L;
私有字符串用户名;
私有字符串密码;
私有字符串昵称;
私有字符串消息;
私有布尔校验;
私人关系主义者;
私有布尔等值线;
私有布尔buddyRequest;
私有字符串buddyRequestAccount;
公共ClientObject(字符串用户名、字符串密码){
this.userName=用户名;
this.password=密码;
this.checkAcc=false;
this.buddyList=新建LinkedList();
this.isOnline=false;
this.buddyRequest=false;
this.buddyRequestAccount=null;
}
…getter和setter的方法
}
我希望我已经清楚地了解了这个问题,我将感谢您的每一个回答,无论如何,谢谢。我想您正在编写发送代码:
.....
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的评论,我已经更新了帖子,为运营部提供了正确的信息。
第一次通过
ObjectOutputStream
将ClientObject
的对象发送到OutputStream
后,下次发送ClientObject
的更改对象时,java将检查此类型的对象是否已被序列化。因为它已经被序列化了,所以java不会再次序列化新创建的对象。这就是为什么你们在另一边得到同样的物体
解决此问题的方法是,每次要发送ClientObject
的已更改对象时,请重置ObjectOutputStream
如下所示:
send.reset();
然后将更改的对象发送到另一端。
我猜您正在编写发送代码:
.....
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的评论,我已经更新了帖子,为运营部提供了正确的信息。
第一次通过ObjectOutputStream
将ClientObject
的对象发送到OutputStream
后,下次发送ClientObject
的更改对象时,java将检查此类型的对象是否已被序列化。因为它已经被序列化了,所以java不会再次序列化新创建的对象。这就是为什么你们在另一边得到同样的物体
解决此问题的方法是,每次要发送ClientObject
的已更改对象时,请重置ObjectOutputStream
如下所示:
send.reset();
然后将更改的对象发送到另一端。
只需调用ObjectOutputStream.reset(),或使用writeUnshared()。只需调用ObjectOutputStream.reset(),或使用writeUnshared()即可.显示序列化和发送ClientObject对象的代码这里是我没有放完整代码的链接,因为它有点复杂mainClient
是ClientObject的类型,在此代码示例中,它是第一次初始化并发送到服务器。第二次发送对象的代码是什么?链接,用于在将主对象发送到服务器之前设置主对象的两个字段。如您所见,setBuddyRequest
和setBuddyRequestAccount
在发送之前已更改。服务器线程等待接收对象的while语句的链接