Java Socket和ServerSocket通信死锁

时间:2019-05-07 00:09:24

标签: java multithreading sockets server serversocket

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

游戏服务器线程(可运行的实现)从每个接收“向 snake [i] 蛇的对象”和“向 dirInput 的char变量”客户使用套接字输入流,并使用套接字输出流发送“蛇对象数组”和“苹果对象苹果”。 Snake对象和Apple对象都是可序列化的。

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

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客户端线程(可运行的实现)将“ Snake对象 mySnake ”和“ char变量 inputControl ”发送到服务器并接收“ int

变量, 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();
        }
    }
}

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

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

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

1 个答案:

答案 0 :(得分:0)

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