Java Socket与ServerSocket通信死锁

标签 java multithreading sockets server serversocket

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

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

这里,clientSocket数组包含所有已连接的客户端套接字,并且这些套接字在玩家结束连接之前不会关闭(这意味着每个玩家的整个游戏过程中都使用一个套接字完成连接)。 board 对象扩展了游戏图形的 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();
            }
        }
    }
}

每个玩家客户端线程(实现 Runnable) 将“Snake 对象 mySnake”和“char 变量 inputControl”发送到服务器并接收“int”变量为 playerNumber','Snake 对象数组为 board.snakes' 以及来自服务器的 'Apple 对象为 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();
        }
    }
}

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

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

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

最佳答案

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

关于Java Socket与ServerSocket通信死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56013864/

相关文章:

java - 我的 tomcat 正在运行,但我无法连接到 http ://localhost:8080

java - 为什么 javac 不接受 `x = x+++++y` ?

java - 如果我们在 start 方法而不是 run 方法中执行整个 Thread 功能,会发生什么?

ruby - 给定多个参数时 File#print 是原子的吗?

python - 使用 tkinter 获取多行(域名)

java - 如何在不使用任何集合和循环的情况下删除 List<MyObject> 中的重复对象

java - (TeeChart - Java) 评估版性能问题

java - 安卓 : AsyncTask onPostExecute is getting null reply

sockets - HTTP/1.1如何解决TCP重置问题?

Perl IO::Socket::INET + IO::Async::Stream 断开连接时重新连接到 TCP 服务器