对象 Input/Output 通过线程中的套接字
Object Input/Output via sockets in a Thread
我正在编写一个基于本地网络的多人游戏。因此,我必须通过套接字将 "player object" 从一个程序发送到另一个程序,反之亦然。因为我不想减慢或使更新和渲染游戏的线程复杂化,所以我创建了一个 "server thread" 和一个 "client thread",它们始终相互通信。
播放器对象的属性经常更改(例如,当您移动时)。所以我向两个新线程添加了一个更新方法,它从主 class.
导入不断变化的播放器对象
服务器线程的代码:
导入java.net.;
导入 java.io.;
public class 服务器实现 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;
}
}`
问题是:收到的对象没有改变,虽然原来的播放器对象改变了。
是因为 main class 调用的 update 方法与 运行 方法中永远持续的 while 循环不并行吗?
我真的不知道.. :( 请帮忙
问题是:收到的对象没有改变,虽然原来的播放器对象改变了。
我认为问题存在于您将对象写入流的方式中。每次调用 out1.writeObject(myPlayer)
时,还应调用 out1.flush()
和 output.reset()
。调用 flush()
将确保如果您最终对输出流进行任何缓冲,将写入任何缓冲的未写入字节。
reset()
调用在幕后所做的事情稍微复杂一些。您的输出流将维护它已经写入的所有对象的列表。如果你第二次写你的 myPlayer
对象而不重置流,流会认为它已经发送了它并告诉客户端使用以前收到的那个对象的版本,让你的客户端看起来它每次都得到相同的对象。
这样做的原因是为了在多次写入同一个对象的情况下节省带宽。例如,假设 myPlayer
有一个复杂的对象层次结构,指向 myPlayer
参考图中不同位置的第二个对象 myObject
。在这种情况下,你不会希望每次看到它时都写 myObject
,所以 ObjectInput/OutputStreams 跟踪已经 received/sent 的内容,并在遇到重复对象时传递一个 ID参考。在对 writeObject(obj)
的调用之间调用 reset()
会强制每次清除 send/receive 状态,以便每次都重写 myPlayer
。
潜在的并行问题
正如其他人评论的那样,您正在 while
循环之外修改 myPlayer
并将其写入套接字。如果对 myPlayer
的修改发生在它被写入套接字的同一时间,这可能是危险的。您可能应该将对 myPlayer
的所有访问放在 synchronized
块内,以防止并发 read/write 问题。
我正在编写一个基于本地网络的多人游戏。因此,我必须通过套接字将 "player object" 从一个程序发送到另一个程序,反之亦然。因为我不想减慢或使更新和渲染游戏的线程复杂化,所以我创建了一个 "server thread" 和一个 "client thread",它们始终相互通信。 播放器对象的属性经常更改(例如,当您移动时)。所以我向两个新线程添加了一个更新方法,它从主 class.
导入不断变化的播放器对象服务器线程的代码:
导入java.net.; 导入 java.io.;
public class 服务器实现 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;
}
}`
问题是:收到的对象没有改变,虽然原来的播放器对象改变了。 是因为 main class 调用的 update 方法与 运行 方法中永远持续的 while 循环不并行吗? 我真的不知道.. :( 请帮忙
问题是:收到的对象没有改变,虽然原来的播放器对象改变了。
我认为问题存在于您将对象写入流的方式中。每次调用 out1.writeObject(myPlayer)
时,还应调用 out1.flush()
和 output.reset()
。调用 flush()
将确保如果您最终对输出流进行任何缓冲,将写入任何缓冲的未写入字节。
reset()
调用在幕后所做的事情稍微复杂一些。您的输出流将维护它已经写入的所有对象的列表。如果你第二次写你的 myPlayer
对象而不重置流,流会认为它已经发送了它并告诉客户端使用以前收到的那个对象的版本,让你的客户端看起来它每次都得到相同的对象。
这样做的原因是为了在多次写入同一个对象的情况下节省带宽。例如,假设 myPlayer
有一个复杂的对象层次结构,指向 myPlayer
参考图中不同位置的第二个对象 myObject
。在这种情况下,你不会希望每次看到它时都写 myObject
,所以 ObjectInput/OutputStreams 跟踪已经 received/sent 的内容,并在遇到重复对象时传递一个 ID参考。在对 writeObject(obj)
的调用之间调用 reset()
会强制每次清除 send/receive 状态,以便每次都重写 myPlayer
。
潜在的并行问题
正如其他人评论的那样,您正在 while
循环之外修改 myPlayer
并将其写入套接字。如果对 myPlayer
的修改发生在它被写入套接字的同一时间,这可能是危险的。您可能应该将对 myPlayer
的所有访问放在 synchronized
块内,以防止并发 read/write 问题。