Java serializable对象中的ArrayList未进行写共享/读非共享(通过网络)
我正在开发一个基于我自己的客户机-服务器体系结构的Java多人游戏。简言之,客户端每秒30次请求服务器的世界对象的副本,并在收到副本后将其客户端副本设置为响应。这一切都是使用Java的标准NetAPI完成的 我遇到的问题是,我还存储了世界上玩家对象的ArrayList,当我将一个玩家添加到此列表时,客户端不会得到更新。它仍然从服务器接收世界的副本,但它不是最新的 在过去的一个项目中,我遇到了一个类似的问题,它是由write/readObject引起的,并且使用write/readUnshared修复了它,但即使这样也不起作用。 以下是通信服务器端的重要信息:Java serializable对象中的ArrayList未进行写共享/读非共享(通过网络),java,networking,arraylist,Java,Networking,Arraylist,我正在开发一个基于我自己的客户机-服务器体系结构的Java多人游戏。简言之,客户端每秒30次请求服务器的世界对象的副本,并在收到副本后将其客户端副本设置为响应。这一切都是使用Java的标准NetAPI完成的 我遇到的问题是,我还存储了世界上玩家对象的ArrayList,当我将一个玩家添加到此列表时,客户端不会得到更新。它仍然从服务器接收世界的副本,但它不是最新的 在过去的一个项目中,我遇到了一个类似的问题,它是由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)
...
您可以在这里看到,即使请求编号匹配,世界对象中玩家对象的数量之间也存在明显的差异
以下是来自世界和玩家职业的重要信息,供好奇者参考:
public class World implements Serializable
{
public ArrayList<Room> rooms;
public ArrayList<Player> players;
private QuickMaths qm;
我很抱歉,如果这是一个长期而容易的问题。我不确定这是引用问题还是其他网络怪癖,但这真的让我发疯了。提前感谢。您的问题在于书面共享,这有点误导。 阅读: “请注意,上述规则仅适用于基本级别 对象以writeUnshared写入,而不是以传递方式写入 要序列化的对象图中引用的子对象。“ 这意味着不会写入播放器对象两次,但将使用序列化树中对该对象的旧引用 解决方法是在每次写入调用后调用该方法,以确保旧的写入对象不会再次被引用 因此:
我正要给你写回信,突然它关闭了。你的问题是写作不共享。子对象仍然是共享的,因此不会重写播放器。每次写入后使用重置方法写入一个新对象。难以置信!-我还没有在任何地方看到记录!!我会试着这样做,看看是否有效。非常感谢。编辑:事后使用reset()实际上是可行的。问题解决了。啊哈-我希望他们不要关闭这个。。。。无论如何,请参见:“请注意,上述规则仅适用于使用writeUnshared编写的基本级别对象,而不适用于要序列化的对象图中的任何传递引用子对象。”@JB Nizet我认为应该重新打开此规则。虽然解决方案大致相同,但这里的用户依赖于writeUnshared,这往往会产生误导。也许标题应该被编辑,但我不认为这个问题应该结束。不管怎样,你的电话。@zipo13我重新开始了这个问题。
public class Player implements Serializable
{
private double xPos;
private double yPos;
private Color color;
int id;
...
out.writeUnshared(main.world);
out.flush();
out.reset();