I have a client/server application in Java, which communicate by serialize/deserialize objects. Typically client sends RequestObj, and server responds with ResponseObj. Server also send heartbeat RequestObj, and client responds with heartbeat ResponseObj.
//Sample RequestObj
public class RequestObj implements Serializable {
private static final long serialVersionUID = xxxx; //auto generated
int type; //TYPE_HEARTBEAT
long time;
...
public void setTime() {
this.time=System.currentTimeMillis();
}
}
When sending heart beat request from the server to each client, it reuse the same RequestObj (per connection), set with current time, and then send to the client. I am expecting to receive the RequestObj with the currect time. However, it seems the RequestObj deserialized at the client always give me the wrong time. In fact the RequestObj received the client is exactly the same (same object id/address) as the first heartbeat RequestObj. But the time in not updating?
//Sample Server side code sending heartbeat
public class ServerSocketWrapper {
Socket socket;
ObjectOutputStream oos;
...
RequestObj heartbeat = New RequestObj(TYPE_HEARTBEAT);
public void sendHeartBeat() {
heartbeat.setTime();
logger.info("HeartBeat {} {}", heartbeat.time, formatFullTime(heartbeat.time));
oos.writeObject(heartbeat);
oos.flush();
}
}
Here is some sample client code:
//Sample Client side code receiving heartbeat
public class ClientSocketWrapper {
Socket socket;
ObjectInputStream ois;
long heartbeatTime;
...
public void run() {
while(true) {
Object obj = ois.readObject();
if (obj instanceof RequestObj) {
RequestObj req = (RequestObj) obj;
if (req.type == TYPE_HEARTBEAT) {
heartbeatTime = req.time;
logger.info("Received heartbeat {} {} {}", heartbeatTime, formatFullTime(heartbeatTime), req);
sendResponse(new ResponseObj(req.id, TYPE_HEARTBEAT));
}
}
...
}
}
}
Here are the logs
logs on the server
16:33:56.186 [pool-2-thread-2] INFO ServerSocketWrapper - HeartBeat 1352842436186 2012-11-13 16:33:56.186
16:34:56.185 [pool-2-thread-2] INFO ServerSocketWrapper - HeartBeat 1352842496185 2012-11-13 16:34:56.185
16:35:56.185 [pool-2-thread-1] INFO ServerSocketWrapper - HeartBeat 1352842556185 2012-11-13 16:35:56.185
logs on the client
16:34:08.510 [server:port] INFO ClientSocketWrapper - Received heartbeat 1352842436186 2012-11-13 16:33:56.186 RequestObj@8497904
16:35:06.758 [server:port] INFO ClientSocketWrapper - Received heartbeat 1352842436186 2012-11-13 16:33:56.186 RequestObj@8497904
16:36:10.303 [server:port] INFO ClientSocketWrapper - Received heartbeat 1352842436186 2012-11-13 16:33:56.186 RequestObj@8497904
Why the time received on the client side is not updating? Is JVM doing some sort of object caching? Server is running w/ jdk 1.7.07 64b, while client on jdk 1.6.31 64b.
If write a single object more than once using the same
ObjectOutputStream, theObjectOutputStreamwill recognize that it has already seen that object and encode it as a reference to the existing object. This is how serialization is able to preserve reference aliasing.If you don’t want reference tracking across messages, construct a new
ObjectOutputStreamandObjectInputStreampair for each new message (or#resettheObjectOutputStreamand#readUnsharedfrom theObjectInputStream). If you don’t do either of these, but instead never modify and reuse message objects, you won’t have the problem of modifications not being seen, but you’ll instead leak resources since theObjectInputStreamwill hold a strong reference to every object it’s ever deserialized.