为什么客户端程序通过Java TCP套接字从服务器获取不正确的数据?
我正在尝试使用套接字和基本图形库Swing/AWT用Java实现一个简单的多人游戏。这个游戏的基本思想就是玩家可以用箭头键在屏幕上移动一个方块图像,同时看到其他玩家移动他们的方块 我编写了一个服务器和一个客户端程序,到目前为止,我只用两名玩家测试了这个游戏。当玩家不同时移动时,游戏运行正常,但当他们同时移动时,会发生以下错误:为什么客户端程序通过Java TCP套接字从服务器获取不正确的数据?,java,swing,sockets,tcp,Java,Swing,Sockets,Tcp,我正在尝试使用套接字和基本图形库Swing/AWT用Java实现一个简单的多人游戏。这个游戏的基本思想就是玩家可以用箭头键在屏幕上移动一个方块图像,同时看到其他玩家移动他们的方块 我编写了一个服务器和一个客户端程序,到目前为止,我只用两名玩家测试了这个游戏。当玩家不同时移动时,游戏运行正常,但当他们同时移动时,会发生以下错误: Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 19140540
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 19140540
at simplegameclient.Window.setCoordinates(SimpleGameClient.java:111)
因此,错误可以追溯到客户端程序中的第111行,在该行中,我试图根据ID为数组元素设置一个新值。由于某种原因,我从服务器获得的ID是如此随机大的数字,因此set操作失败,导致此错误。我不明白的是,服务器怎么可能给我这么大的ID,因为目前可能给客户端的最大ID是7?我的意思是,从哪里突然得到这么大的数字?应用程序逻辑是否有问题,或者TCP是否正在丢失数据包,并且错误是由此引起的
下面可以看到来源。我知道这可能不是非常有效和漂亮的代码,因为我还在学习网络方面的东西。因此,我希望大家关注的是主要问题,而不是次要问题
SimpleGameServer.java
package simplegameserver;
import java.io.*;
import java.net.*;
import deliverable.Packet;
public class SimpleGameServer {
public static final int MAX_USERS = 8;
public static int USERS_ONLINE = 0;
static ServerSocket serverSocket;
static Socket socket;
static DataInputStream in;
static DataOutputStream out;
static ObjectOutputStream oout;
static User[] users = new User[MAX_USERS];
public static void main(String[] args) throws IOException {
System.out.println("Starting server...");
serverSocket = new ServerSocket(7777);
System.out.println("Server started.");
while (true) {
socket = serverSocket.accept();
System.out.println("Connection from: " + socket.getInetAddress());
if (USERS_ONLINE == MAX_USERS) {
out = new DataOutputStream(socket.getOutputStream());
out.writeUTF("Server full. Try again later.");
socket.close();
continue;
}
for (int i=0; i<MAX_USERS; i++) {
if (users[i] == null) {
USERS_ONLINE++;
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
oout = new ObjectOutputStream(socket.getOutputStream());
users[i] = new User(in,out,users,i,oout);
Thread t = new Thread(users[i]);
t.start();
break;
}
}
}
}
}
class User implements Runnable {
private DataInputStream in;
private DataOutputStream out;
private User[] users = new User[SimpleGameServer.MAX_USERS];
private int id;
private int idin, xin, yin;
private ObjectOutputStream oout;
User(DataInputStream in, DataOutputStream out, User[] users, int id, ObjectOutputStream oout) {
this.in = in;
this.out = out;
this.users = users;
this.id = id;
this.oout = oout;
}
@Override
public void run() {
System.out.println("Thread started for new user.");
try {
out.writeInt(id);
System.out.println("Id sent");
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
try {
idin = in.readInt();
xin = in.readInt();
yin = in.readInt();
Packet p = new Packet(idin,xin,yin);
for (int i=0; i<SimpleGameServer.MAX_USERS; i++) {
if (users[i] != null) {
try {
users[i].oout.writeObject(p);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
this.users[id] = null;
break;
}
}
SimpleGameServer.USERS_ONLINE--;
}
}
来吧,在你做任何其他事情之前,先读一下这本书
out = new DataOutputStream(socket.getOutputStream());
oout = new ObjectOutputStream(socket.getOutputStream());
两个流共享同一个流?这不是一个好主意。如果这是问题所在,你能解释一下这会如何导致一个随机大数突然出现吗?当你从一个由两个源写入的流中读取数据时,你不认为你很有可能会读取垃圾吗?阅读本教程,它完全是为您编写的。因此,我从本教程中得到的信息和您的回答是,我应该始终为套接字检索1个输入和1个输出流,以避免类似的问题?如果是的话,那就公平了。在服务器的用户线程中仍然有一行代码让我担心:users[i].oot.writeObjectp;。假设两个用户向服务器发送数据,服务器的两个用户线程同时开始写入过程。这些写操作是按顺序发生还是同时发生?教程中没有提到这一点。它们发生得很正确,所以您不必担心网络的这一部分。顺便说一下,我会避免使用ObjectStreams。如果你想知道原因,请仔细阅读他们的文档。
package deliverable;
import java.io.Serializable;
public class Packet implements Serializable {
private int id;
private int x, y;
public Packet(int id, int x, int y) {
this.id = id;
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getID() {
return id;
}
}
out = new DataOutputStream(socket.getOutputStream());
oout = new ObjectOutputStream(socket.getOutputStream());