【问题标题】:ObjectInputStream does not read all objects from the output stream [duplicate]ObjectInputStream 不会从输出流中读取所有对象[重复]
【发布时间】:2019-12-12 10:29:12
【问题描述】:

我正在尝试通过套接字将对象从服务器发送到渲染客户端。第一个实体对象列表由 8 个实体组成,但列表中添加了更多实体。我的服务器最终可以将数百个对象写入 ObjectOutputStream,但客户端只读取最初的 8 个。

我尝试在 writeObject 方法之前和之后调用 flush(),但这似乎没有什么区别。我已将问题缩小到客户端。

服务器使用此方法将 ArrayList 写入流:

private void sendEntities() {
    try {
        ArrayList<Entity> entities = engine.requestEntities();
        System.out.println("Entities sent: " + entities.size());
        objectOut.writeObject(entities);
        // objectOut.flush(); Does not fix the problem
    } catch (IOException e) {
        e.printStackTrace();
    }
}

客户端读取对象并将其返回给在屏幕上绘制对象的 setter 方法,但这是尝试从流中读取对象的唯一区域。

private ArrayList<Entity> requestEntities() {
    try {
        out.writeUTF("REQ_ENT()");
        // The client only receives 8 entity-objects every time
        ArrayList<Entity> entitiesReceived = (ArrayList<Entity>) objectIn.readObject();
        in.readUTF();
        return entitiesReceived;

    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    return null;
}

我希望从输入流读取的对象列表与写入输出流的对象数量相匹配,但从输入流读取的列表保持不变。它在第一次调用 requestEntities() 时按预期工作,但在后续调用时不会。

编辑:已添加到 github 存储库的链接

编辑 2:正如 Johannes Kuhn 所指出的,ObjectOutputStream 发送对先前发送的对象的引用。 我添加了一行代码,似乎已经解决了这个问题。我制作了实体列表的副本,然后将此副本写入流。

private void sendEntities() {
    try {
        ArrayList<Entity> entities = engine.requestEntities();
        ArrayList<Entity> copy = new ArrayList<>(entities);
        System.out.println("Entities sent: " + entities.size());
        objectOut.writeObject(copy);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Link to github repository

【问题讨论】:

  • 我认为您在向我们展示的代码之外的某个地方存在错误。您对 ObjectInputStream/ObjectOutputStream 的期望是正确的,这里贴出的代码没有明显的问题。
  • 我尝试将其保留在造成问题的部分,但我可以发布 github 链接以进行进一步检查。
  • 如果您继续发送相同的列表,您将得到相同的列表,没有任何变化。始终发送新副本。
  • 你为什么打电话。 readUTF(),并在你没有调用writeUTF()的时候把结果扔掉?
  • 我使用 writeUTF 从服务器请求不同的元素,我曾经使用 readUTF 进行响应(主要是测试套接字通信);但既然你提到它,它似乎是多余的。

标签: java sockets objectinputstream objectoutputstream


【解决方案1】:

问题在于 ObjectStreams 会跟踪已经发送的对象,而不是再次发送它们,它们只会引用前一个对象。

复制您的 ArrayList 并发送新的 ArrayList。

tl;dr:序列化不适用于服务器/客户端通信。

【讨论】:

  • 哦,我不知道,文档中哪里有这样说的?除了使用序列化进行服务器/客户端通信之外,您还有其他建议吗?
  • 它可能在规范中的某个地方。我要么推荐 DataOutputStream 或其他协议。 ObjectInputStream 必须保留对所有读取对象的引用,因此在关闭 OIS 之前可能会有一些内存泄漏。
  • 您应该提到reset()writeUnshared() 作为可能的解决方案。 NB 序列化用于 RMI 和 JMS 中的客户端/服务器通信。
  • 两者都处理所有这些影响。尽管如此,用 Java 以外的其他语言为 RMI 或 JMS 编写客户端还是很困难的。我更喜欢使用 JSON,或者其他一些绑定到其他语言的协议。
猜你喜欢
  • 1970-01-01
  • 2018-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-03
  • 2016-04-30
  • 2013-07-07
相关资源
最近更新 更多