可序列化对象中的ArrayList不带有writeUnshared / readUnshared(通过网络)

时间:2018-10-15 18:56:27

标签: java networking arraylist

我正在用自己的客户端-服务器体系结构开发Java多人游戏。简而言之,客户端每秒请求服务器的World对象的副本30次,并且在接收到该副本之后,将其客户端副本设置为响应。这一切都使用Java的标准net API完成。

我遇到的问题是,我还在世界上存储了一个Player对象的ArrayList,并且当我将Player添加到此列表中时,客户端无法获取更新。它仍然从服务器接收世界的副本,但是不是最新的。

在过去的项目中,我遇到了类似的问题,该问题是由write / readObject引起的,并通过使用write / readUnshared进行了修复,但即使这样也不起作用。

以下是通信服务器端的重要内容:

String message;
int sum = 0;
while(active)
{
    message = "";
    try {
        message = in.readUTF();
    } catch (IOException e) {
        active = false;
        System.out.println("Lost connection with client " + socket.getInetAddress());
    }

    if(message.equals("GETWORLD"))
    {
        try {
            sum++;
            if(sum == 100)
                main.world.addPlayer(999, 2, 2);
            System.out.println("Client requested world (#" + sum + ")");
            System.out.println(main.world.players.size());
            out.writeUnshared(main.world);
            out.flush();
            System.out.println("Sent client world (#" + sum + ")");
        } catch (IOException e) {
            active = false;
            System.out.println("Lost connection with client " + socket.getInetAddress());
        }
    }

    if(message.equals("DISCONNECT"))
    {
        active = false;
        System.out.println("Client " + socket.getInetAddress() + " requested disconnect");
    }
}

然后是客户端:

Object read = null;
int sum = 0;
while(active)
{
    try {
        Thread.sleep((long)(1000 / 30.0));

        if(connected)
        {
            sum++;
            System.out.println("Asking server for world (#" + sum + ")");
            out.writeUTF("GETWORLD");
            out.flush();

            read = in.readUnshared();
            if(read instanceof World)
            {
                World temp = (World)read;
                System.out.println(temp.players.size());
                frame.panel.updateWorld((World)read);
                System.out.println("Got world from server (#" + sum + ")");
            }
        }
    } catch (InterruptedException | ClassNotFoundException e1) {
        active = false;
        e1.printStackTrace();
    } catch (IOException e2) {
        active = false;
        System.out.println("Lost connection with server @ " + socket.getInetAddress());
        frame.dispose();
        System.exit(0);
    }
}

显然,sum变量用于调试。 我用一些输出进一步测试了这一点,这是令我恐惧的地方:

Client log:
...
Asking server for world (#99)
1
Got world from server (#99)
Asking server for world (#100)
1
Got world from server (#100)
Asking server for world (#101)
1
Got world from server (#101)
...

Server log:
...
Client requested world (#99)
1
Sent client world (#99)
Client requested world (#100)
2
Sent client world (#100)
Client requested world (#101)
2
Sent client world (#101)
...

您可以在此处看到,即使请求号匹配,World对象中Player对象的数量也存在明显差异。

以下是来自World和Player类的重要内容:

public class World implements Serializable
{

    public ArrayList<Room> rooms;
    public ArrayList<Player> players;

    private QuickMaths qm;

...

public class Player implements Serializable
{

    private double xPos;
    private double yPos;
    private Color color;

    int id;
    ...

很抱歉,这是一个长期而又简单的问题。我不确定这是参考问题还是其他网络怪癖,但这确实使我发疯。预先感谢。

1 个答案:

答案 0 :(得分:1)

您的问题是与writeUnshared有点误导。 阅读here

  

”请注意,上述规则仅适用于基本级别   用writeUnshared编写的对象,并且不传递给任何对象   要序列化的对象图中的被引用子对象。 “

这意味着播放器对象不会被写入两次,而是将使用序列化树中对该对象的旧引用。

解决方案是在每次写调用之后调用reset方法,以确保不会再次引用旧的写对象。

所以:

out.writeUnshared(main.world);
out.flush();
out.reset();