7

我只是从一本 java 书中学习网络,所以我有点菜鸟。我在书上或网上都找不到这个问题,所以我决定上网问问。

书中说使用 ObjectOutputStream 和 ObjectInputStream 将对象发送和接收到不同的控制台。

现在,我能够成功接收我发送的对象——但只能接收一次。当我发送不同的对象:随机字符串和整数以及无名实例时,控制台具有所有正确的字段。但是当我发送一个对象的实例,更改一个实例字段的值,然后重新发送该对象时,inpustream 会加载原始实例的值。

因此,例如,我有一个公共 int“var”等于 1 的类的实例。如果我发送这个类的实例,客户端会收到它并正确报告 var = 1。但是,如果我改变var 到 2(在同一个实例中)并重新发送它,客户端将完成调用 read() 方法(所以它必须收到新对象!),但它会报告 var 为 1。如果我将实例发送到另一个尚未收到实例的客户端,它会正确地将 var 报告为 2,即使我更改 var 也会继续报告为 2。

如果客户端之前没有收到实例,它会读取正确版本的实例,这一事实必须意味着对象正在通过输出流正确发送;由于某种原因,输入流无法正常工作。几乎就像它看到它是同一个对象,所以它假定它具有相同的值而无需检查。为什么会发生这种情况,我该如何解决?

抱歉,如果我问的是愚蠢的问题——这本书没有解释序列化和套接字是如何工作的,只是解释了如何使用它们,所以我很可能对如何使用它们从根本上感到困惑。谢谢!

我为测试问题而编写的简单代码:

服务器:(有一个定时器动作来不断发送更新的对象)

    public void actionPerformed(ActionEvent e)
{
    object.var++;
            output.write(object);
            output.flush();
            System.out.println(object.var);
}

客户

    public void run()
{
    while(true)
            {
                   Test t = (Test)input.readObject();
                   System.out.println(t.var);
            }
    }

当这些程序运行时,Server 类的输出是 1,2,3,4... 无限增加,而 Client 类的输出只是 1,1,1,1,1,1,1 等。

感谢您抽出时间来阅读。对不起,如果我只是愚蠢,我对这个东西很陌生。

编辑:对不起, read() 是错误类型(我手动输入代码,因为我无法正确格式化),我的意思是 input.readObject()

4

3 回答 3

17

原因是ObjectOutputStream如果同一对象被写入两次,则缓存对象引用并将反向引用写入流。这意味着当您write第二次调用流时,实际上并没有写入对象的新副本,它只是插入对已经写入的对象的引用。

ObjectOutputStream.reset您可以通过在 write 调用之间调用来防止这种情况。这告诉流丢弃任何缓存的引用。

这种行为看起来很奇怪,但如果您尝试序列化具有循环引用的对象图(即编写引用对象 B 的对象 A 反过来又引用回对象 A),则实际上有必要防止无限循环。

于 2011-06-15T03:58:08.167 回答
3

您使用的是 ObjectInputStream中的read()还是readObject() ?如果您使用的是 read() ,那么您只会得到一个字节的数据。尝试转换客户端

public void run()
{
  while(true)
  { 
    Test t = (Test)input.readObject();
    System.out.println(t.var);
  }
}

编辑:应该是 input.readObject();

于 2011-06-15T03:06:20.993 回答
-1

我花了很多时间调试这样的代码。:)

我不确定对此的正确解决方案是什么,但是如果您创建对象的新实例,或者只是 clone() 它,在发送它之前代码应该按预期工作。

似乎虚拟机将它接收的对象识别为它已经拥有的对象,并简单地更新客户端的指针,而无需实际检查是否有任何更改。

尝试...

public void actionPerformed(ActionEvent e)
{
    object.var++;
    //assuming your object supports clone()
    output.write(object.clone());
    output.flush();
    System.out.println(object.var);
}
于 2011-06-15T03:05:19.633 回答