问题
I used the ObjectStream in Socket to transport the class. The client transports two different data in same class, but the server gets the second data that is same as the first data. It is strange!
Here is my code of client:
public Client()
{
MessageClass messageobject=new MessageClass("login");
messageobject.SetLoginUserInfo("18580409","12345","magicgiant");
try
{
client=new Socket("localhost",1234);
System.out.println("Connected!");
ObjectOutputStream out=new ObjectOutputStream(client.getOutputStream());
out.writeObject(messageobject);
out.flush();
System.out.println(1);
messageobject.inquire=true;
messageobject.SetLoginUserInfo("122131","21312","dfsd");
out.writeObject(messageobject);
out.flush();
System.out.println(2);
}
catch(Exception e)
{
System.out.println(e);
}
}
Here is my server:
public void run()
{
try
{
is=new ObjectInputStream(client.getInputStream());
}
catch (Exception ex)
{
System.out.println(ex);
}
while(true){
try
{
MessageClass messageobject = (MessageClass)is.readObject();
System.out.println(messageobject.GetLoginId()+messageobject.GetLoginPassword());
idSocketItem = new IdSocket(messageobject.GetLoginId(),client,messageobject);
s.idSocketList.addElement(idSocketItem);
}
catch (Exception ex)
{
System.out.println(ex);
}
}
}
The System.out in server should be
1858040912345
12213121312
But the real result is
1858040912345
1858040912345
I have tried to cancel the flush(), but it does not work. Where is the problem?
回答1:
The problem is that you're writing the same reference twice:
out.writeObject(messageobject);
out.flush();
System.out.println(1);
messageobject.inquire=true;
messageobject.SetLoginUserInfo("122131","21312","dfsd");
out.writeObject(messageobject);
ObjectOutputStream
caches the fact that you've written that reference, and just emits a token to refer to the previous value. Three options to consider:
- (Preferred, IMO): Create a new object instead of modifying the existing one
- Call writeUnshared() instead of
writeObject()
:This method is identical to writeObject, except that it always writes the given object as a new, unique object in the stream (as opposed to a back-reference pointing to a previously serialized instance).
Call reset() on the stream after writing the first object:
Reset will disregard the state of any objects already written to the stream. The state is reset to be the same as a new ObjectOutputStream. The current point in the stream is marked as reset so the corresponding ObjectInputStream will be reset at the same point. Objects previously written to the stream will not be refered to as already being in the stream. They will be written to the stream again.
I prefer the first version as logically you've got two different messages - so they should be two different objects.
Additionally, I'd strongly encourage you to start following Java naming conventions, and make all your fields private to encourage encapsulation.
来源:https://stackoverflow.com/questions/17009368/how-to-use-readobject-twice-in-socket-of-java