【问题标题】:Java, when calling readObject() on an ObjectOutputStream it is only returning one valueJava,在 ObjectOutputStream 上调用 readObject() 时,它只返回一个值
【发布时间】:2012-05-05 00:30:06
【问题描述】:

我正在编写服务器/客户端游戏。我的客户端向服务器发送一条消息,服务器应该将该消息分发给连接到服务器的所有其他客户端。我遇到的问题是,当我调用 ois.readObject() (其中 ois 是从 ServerSocket accept() 调用创建的 ObjectInputStream )时,它只返回我写入客户端相应 ObjectOutputStream 的第一个值.

这是我的服务器为每个连接的客户端创建的线程的代码。

@Override
public void run() {
    Iterator<ClientThread> itr = null;
    ClientThread ct = null;
    Object recObj = null;
    try {
        oos.writeObject(id);
        oos.flush();

        while(oos != null && ois != null) {
            recObj = ois.readObject();
            System.out.println(recObj);
            if(recObj instanceof Player) {
                System.out.println("[" + id + "] Recieved player from client.");

                player = (Player) recObj;
                Server.playerMap.put(player.getId(), player);

                if(player == null) {
                    System.out.println("Player " + player.getId() + " has joined the server.");
                }

                itr = Server.threadList.iterator();
                while(itr.hasNext()) {
                    ct = itr.next();
                    if(!(ct.id == this.id)) {
                        ct.oos.writeObject(recObj);
                        ct.oos.flush();
                        System.out.println("Sending " + (Player) recObj + " to client " + ct.id + "!");
                    } else {
                        System.out.println("Don't send stuff to " + ct.id + " or we get an infinite loop!");
                    }
                }
            } else {
                System.err.println("Recieved something other than a Player object.");
            }
        }
    } catch (IOException e) {
        System.err.println("[INFO] " + e.getLocalizedMessage());

    } catch (ClassNotFoundException e) {
        System.err.println(e.getLocalizedMessage());
        e.printStackTrace();
    }
    cleanup();
}

此代码适用于每个客户端创建的线程。

@Override
public void run() {
    Object recObj = null;
    Player newPlayer = null;
    try {
        recObj = client.ois.readObject();
        if(recObj instanceof Integer) {
            client.player = new Player((Integer) recObj);
            client.playerMap.put(client.player.getId(), client.player);
        } else {
            System.err.println("First object recieved from server was not of type Integer.");
            System.err.println("No valid id has been set.");
        }

        while(client.ois != null) {
            recObj = client.ois.readObject();
            if(recObj instanceof Player) {
                newPlayer = (Player) recObj;
                System.out.println("Recieved " + newPlayer + "!");
                client.playerMap.put(newPlayer.getId(), newPlayer); 
            }
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

附:我意识到我不需要刷新 ObjectOutputStream,但这只是一个测试的想法。

【问题讨论】:

  • 不确定这种方式的线程是否良好,我会将客户端的消息排入处理该客户端的线程中,但它基本上也应该在您的场景中工作。 (希望您不要将新玩家发送给尚未收到其 id 的客户端)。您的发送循环可能会被未读取的客户端阻止,请在写入前后使用 println 进行验证。

标签: java sockets objectoutputstream


【解决方案1】:

每次写入后在 ObjectOutputStream 上调用 .reset。

【讨论】:

  • 成功了!但是为什么每次写完都需要调用reset呢?
  • 它将重置块向下发送到流中,因此阅读器应该为下一个对象重置。如果不这样做,读者只会看到一大块数据。
  • 那么为什么在我编写的另一个没有调用 reset 的程序中没有同样的问题呢?只是运气不好还是只是因为我通过流发送的对象类型?
  • 也不确定为什么需要重置,但如果这是一个持续的过程,不时重置并没有什么坏处,否则带有remebered对象句柄的内存将无休止地增加。
  • @Krrose27 如果调用 reset() 在很大程度上增加了输出文件的大小怎么办。我有大量的对象要写,假设大约 2GB 左右。如果我在每次写入后调用 reset(),输出大小为 5Gb,大约 13 分钟左右。有什么技巧吗?
猜你喜欢
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-12
  • 1970-01-01
  • 1970-01-01
  • 2018-12-30
  • 1970-01-01
相关资源
最近更新 更多