首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >可序列化对象中的ArrayList未传递写入未共享/读取未共享(通过网络)

可序列化对象中的ArrayList未传递写入未共享/读取未共享(通过网络)
EN

Stack Overflow用户
提问于 2018-10-16 02:56:27
回答 1查看 85关注 0票数 1

我正在开发一个基于我自己的客户端-服务器架构的Java多人游戏。简而言之,客户机每秒请求服务器的World object副本30次,并在接收到副本时将其客户端副本设置为响应。这一切都是使用Java的标准net API完成的。

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

我在过去的一个项目中遇到了类似的问题,这是由写/读对象引起的,通过使用写/读不共享来修复它,但即使这样也不起作用。

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

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;
    ...

如果这是一个漫长而简单的问题,我道歉。我不确定这是引用问题还是其他网络问题,但它真的让我抓狂。提前谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-16 03:45:08

你的问题出在writeUnshared上,这有点误导人。阅读here

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

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

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

所以:

out.writeUnshared(main.world);
out.flush();
out.reset();
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52823125

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档