【发布时间】:2018-12-13 01:18:53
【问题描述】:
我正在开发一个围绕我自己的客户端-服务器架构构建的 Java 多人游戏。简而言之,客户端每秒请求服务器 World 对象的副本 30 次,并在收到它后,将其客户端副本设置为响应。这一切都是使用 Java 的标准网络 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;
...
如果这是一个漫长而简单的问题,我深表歉意。我不确定这是参考问题还是其他网络怪癖,但这真的让我发疯。提前致谢。
【问题讨论】:
-
我正要给你写一个答案的时候它关闭了。您的问题与 writeUnshared 有关。子对象仍然是共享的,因此播放器不会被重写。每次写入后使用reset方法写入一个新对象。
-
难以置信——我还没有在任何地方看到过这样的记录!!我会尝试这样做,看看它是否有效。谢谢你。 edit: 之后使用 reset() 实际上确实有效。问题解决了。
-
ahhh - 我希望他们不要关闭这个......无论如何,请参阅here:“请注意,上述规则仅适用于使用 writeUnshared 编写的基本级别对象,而不适用于任何要序列化的对象图中的可传递引用的子对象。"
-
@JB Nizet 我认为应该重新打开这个。虽然解决方案大致相同,但这里的用户依赖 writeUnshared,这通常会产生误导。也许应该编辑标题,但我认为这个问题不应该结束。无论如何,您的电话。
-
@zipo13 我重新打开了这个问题。
标签: java networking arraylist