java - 通过线程中的套接字进行对象输入/输出

标签 java multithreading sockets multiplayer

我正在编写一个基于本地网络的多人游戏。因此,我必须通过套接字将“玩家对象”从一个程序发送到另一个程序,反之亦然。因为我不想减慢更新和渲染游戏的线程或使其复杂化,所以我创建了一个“服务器线程”和一个“客户端线程”,它们始终相互通信。 玩家对象的属性经常变化(例如当您移动时)。因此,我向两个新线程添加了更新方法,该方法从主类导入不断变化的玩家对象。

服务器线程的代码:

导入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/

相关文章:

java - "Routing"threadpoolexecutor 内的任务

WPF 多线程

c - 即使以二进制模式写入后,文件也被损坏

c - Linux : socket and binding issues

javascript - 如何使用 socket.io 判断哪个套接字连接单击了按钮?

java - Thread.currentThread().contextClassLoader.getResource(path) 似乎缓存结果。可以预防吗?

java - 自动组织 JUnit 测试

java - Spring @PropertySources 值不被覆盖

java - 如何设置其他包无法访问该包

java - 跨线程变量的每次读取都应该是 volatile 的、原子性的还是由同步包装的?