简体   繁体   English

通过套接字进行Java对象序列化/反序列化缓存

[英]Java object serialization/deserialization caching over socket

I have a client/server application in Java, which communicate by serialize/deserialize objects. 我有一个Java客户端/服务器应用程序,可通过序列化/反序列化对象进行通信。 Typically client sends RequestObj, and server responds with ResponseObj. 通常,客户端发送RequestObj,而服务器以ResponseObj进行响应。 Server also send heartbeat RequestObj, and client responds with heartbeat ResponseObj. 服务器还发送心跳RequestObj,客户端以心跳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. 当从服务器向每个客户端发送心跳请求时,它会重复使用相同的RequestObj(每个连接),设置为当前时间,然后发送给客户端。 I am expecting to receive the RequestObj with the currect time. 我希望在正确的时间收到RequestObj。 However, it seems the RequestObj deserialized at the client always give me the wrong time. 但是,在客户端反序列化的RequestObj似乎总是给我错误的时间。 In fact the RequestObj received the client is exactly the same (same object id/address) as the first heartbeat RequestObj. 实际上,收到客户端的RequestObj与第一个心跳RequestObj完全相同(对象ID /地址相同)。 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? JVM是否在进行某种对象缓存? Server is running w/ jdk 1.7.07 64b, while client on jdk 1.6.31 64b. 服务器正在使用jdk 1.7.07 64b运行,而客户端在jdk 1.6.31 64b上运行。

If write a single object more than once using the same ObjectOutputStream , the ObjectOutputStream will recognize that it has already seen that object and encode it as a reference to the existing object. 如果使用同一ObjectOutputStream多次写入一个对象,则ObjectOutputStream将识别出它已经看到了该对象,并将其编码为对现有对象的引用。 This is how serialization is able to preserve reference aliasing. 这就是序列化能够保留引用别名的方式。

If you don't want reference tracking across messages, construct a new ObjectOutputStream and ObjectInputStream pair for each new message (or #reset the ObjectOutputStream and #readUnshared from the ObjectInputStream ). 如果您不想跨消息进行引用跟踪,请为每条新消息构造一个新的ObjectOutputStreamObjectInputStream对(或#resetObjectOutputStream#readUnsharedObjectInputStream )。 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 the ObjectInputStream will hold a strong reference to every object it's ever deserialized. 如果您不执行任何一项操作,而是从不修改和重用消息对象,则不会有看不到修改的问题,但是您会浪费资源,因为ObjectInputStream将拥有对每个对象的强引用它曾经被反序列化。

是的,一旦通过ObjectOutputStream发送对象,则重新发送该对象(即使已修改)也将仅发送对先前发送的对象的引用,除非在流上调用reset()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM