我正在编写一个基于本地网络的多人游戏。因此,我必须通过套接字将“玩家对象”从一个程序发送到另一个程序,反之亦然。因为我不想减慢更新和渲染游戏的线程或使其复杂化,所以我创建了一个“服务器线程”和一个“客户端线程”,它们始终相互通信。 玩家对象的属性经常变化(例如当您移动时)。因此,我向两个新线程添加了更新方法,该方法从主类导入不断变化的玩家对象。
服务器线程的代码:
导入java.net。; 导入java.io。;
公共(public)类 Server 实现 Runnable {
ServerSocket serverSocket;
Socket clientSocket;
ObjectOutputStream out1;
ObjectInputStream in1;
Player myPlayer;
Player yourPlayer;
public Server(int portNumber){
try {
serverSocket = new ServerSocket(portNumber);
clientSocket = serverSocket.accept();
out1 = new ObjectOutputStream(clientSocket.getOutputStream());
in1 = new ObjectInputStream(clientSocket.getInputStream());
myPlayer = new Player(100, 100);
myPlayer.init(100, 100);
out1.writeObject(myPlayer);
}catch(IOException e){
System.err.println(e.getMessage());
}
}
public void run(){
while(true) {
try {
yourPlayer = (Player) in1.readObject();
out1.writeObject(myPlayer);
} catch (IOException e) {
System.err.println("ERROR");
}catch(ClassNotFoundException e){
}
}
}
public void update(Player player){
myPlayer = player;
}
public Player getYourPlayer() {
return yourPlayer;
}
}`
问题是:尽管原始玩家对象发生了变化,但接收到的对象没有发生变化。 是因为主类调用的 update 方法不能与 run 方法中持久的 while 循环并行工作吗? 我真的不知道..:(请帮忙
最佳答案
问题是:尽管原始播放器对象发生了变化,但接收到的对象没有发生变化。
我相信问题存在于您将对象写入流的方式中。每次调用 out1.writeObject(myPlayer)
时,还应该调用 out1.flush()
和 output.reset()
。对 flush()
的调用将确保,如果您最终在输出流上进行任何缓冲,任何缓冲的未写入字节都将被写入。
reset()
调用的底层功能稍微复杂一些。您的输出流将维护它已写入的所有对象的列表。如果您在没有重置流的情况下再次写入 myPlayer
对象,则流会认为它已经发送了该对象,并告诉客户端使用之前接收到的该对象的版本,使客户端觉得每次都获取相同的对象。
这样做的原因是为了在多次写入同一个相同对象的情况下节省带宽。例如,假设 myPlayer
有一个复杂的对象层次结构,它指向 myPlayer
引用图中许多不同位置的第二个对象 myObject
。在这种情况下,您不会希望每次看到 myObject 时都编写它,因此 ObjectInput/OutputStreams 会跟踪已接收/发送的内容,并在遇到重复的 Object 引用时传递 ID。在调用 writeObject(obj)
之间调用 reset()
会强制每次清除发送/接收状态,以便每次都重写 myPlayer
。
潜在的并行问题
正如其他人所评论的,您正在将 myPlayer 写入套接字的while
循环之外修改它。如果对 myPlayer
的修改恰好在写入套接字的同时发生,这可能会很危险。您可能应该将对 myPlayer
的所有访问放入 synchronized
block 中,以防止并发读/写问题。
关于java - 通过线程中的套接字进行对象输入/输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38962151/