【问题标题】:Java Socket and ServerSocket Communication deadlockJava Socket 和 ServerSocket 通信死锁
【发布时间】:2019-09-24 14:25:14
【问题描述】:

我正在尝试使用 java Socket 和 ServerSocket 构建一个多人游戏,游戏服务器最多运行 4 个客户端。我在此代码中将客户端数量限制为 1 个以进行测试,并为播放器和服务器使用阻塞 I/O 模型。

游戏服务器线程(实现 Runnable) 从每个线程接收“Snake object to snake[i]”和“char variable to dirInput”客户端使用套接字输入流,并使用套接字输出流发送“Snake object Array snake”和“Apple object apple”。 Snake 对象和 Apple 对象都是可序列化的。

在这里,clientSocket 数组包含所有已连接的客户端套接字,并且这些套接字在玩家结束连接之前不会关闭(这意味着每个玩家的整个游戏过程都使用一个套接字完成连接)。 board 对象为 Game Graphics 扩展了 JComponent(显示游戏玩法)。

public void run()
{
    while(true)
    {
        //playerCount is fixed to 1 for testing
        for(int i=0; i<playerCount; i++)
        {
            try {
                //get every snake object from each player
                ObjectInputStream objectInputStream = new ObjectInputStream(clientSocket[i].getInputStream());
                snake[i] = (Snake)objectInputStream.readObject();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        for(int i=0; i<playerCount; i++)
        {
            try {
                Reader charInputStream = new InputStreamReader(clientSocket[i].getInputStream());
                dirInput = (char) charInputStream.read();

                //DO SOMETHING WITHOUT COMMUNICATION

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        for(int i=0; i<playerCount; i++)
        {
            try {
                OutputStream outputStream = clientSocket[i].getOutputStream();
                outputStream.write(i);

                ObjectOutputStream objectOutputStream = new ObjectOutputStream(clientSocket[i].getOutputStream());
                objectOutputStream.writeObject(snake);
                objectOutputStream.writeObject(apple);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

每个 Player Client Thread (implements Runnable) 发送 'Snake object mySnake' 和 'char variable inputControl' 到服务器并接收 'int变量到 playerNumber','Snake object Array to board.snakes' 和 'Apple object to board.apple' 从服务器。

public void run() {
    while(true)
    {
        try {
            Thread.sleep(50);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(gameSocket.getOutputStream());
            objectOutputStream.writeObject(mySnake);

            Writer charOutputWriter = new OutputStreamWriter(gameSocket.getOutputStream());
            charOutputWriter.write(inputControl);

            playerNumber = gameSocket.getInputStream().read();

            ObjectInputStream objectInputStream = new ObjectInputStream(gameSocket.getInputStream());
            board.snakes = (Snake[])objectInputStream.readObject();
            board.apple = (Apple)objectInputStream.readObject();
            mySnake = board.snakes[playerNumber];

            board.repaint();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

问题是,当我同时启动游戏服务器和客户端并尝试通信时,游戏服务器线程和玩家客户端线程在通信时都卡住了。

当我调试时,游戏服务器线程卡在从客户端线程读取字符输入 (dirInput),而客户端线程卡在从游戏服务器线程读取 int 输入 (playerNumber)。通过看到两个线程都被 InputStream 卡住,我认为在使用 InputStream 时发生了死锁,因为两个线程都试图使用 InputStream。但我不确定死锁是否真的发生了。

如何让两个线程进行通信?我应该为游戏服务器线程和玩家客户端线程使用非阻塞 I/O 模型吗?

【问题讨论】:

  • 您应该为每个套接字创建一次对象流,而不是每次您要读取或写入某些内容时,并且始终在对象输入之前创建对象输出。
  • @user207421 我认为像对象流这样的包装器类为一个套接字“共享”一个 inputStream,因此可以制作尽可能多的包装器流类。我想错了吗?
  • NB (1) 你的睡眠简直就是在浪费时间; (2) 除了通过对象流之外,不要做 I/O。
  • @user207421 感谢您的评论。根据您的建议,我在各处修复了我的代码,但我的程序和以前一样卡在了同一个地方。这是由于服务器线程和客户端线程之间的 inputStream 死锁吗?
  • 您必须在对象输入流之前,在两端创建对象输出流。

标签: java multithreading sockets server serversocket


【解决方案1】:

我不确定你到底做了什么!但问题是你创建了很多次ObjectInputStream!如果您想知道问题出在哪里,只需创建一个扩展 java.io.InputStream 类的简单类,并通过将该类作为基础 来创建一个 ObjectInputStream输入流。你会看到当一个 ObjectInputStream 类创建时,它会尝试读取 4 个字节作为头字节!所以这意味着你丢失了一些数据,这就是你的线程卡住的原因! 如果你有反编译器,你也可以检查 ObjectInputStream 的代码。

【讨论】:

    猜你喜欢
    • 2017-07-02
    • 2020-06-09
    • 2014-05-28
    • 1970-01-01
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    • 2014-11-05
    • 2014-12-21
    相关资源
    最近更新 更多