java - Java Socket 和 ServerSocket 通信死锁
问题描述
我正在尝试使用 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 客户端线程(实现 Runnable)将“Snake object mySnake ”和“char variable inputControl ”发送到服务器,并从“int variable to 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 模型吗?
解决方案
我不确定你到底做了什么!但问题是您多次创建了ObjectInputStream !如果您想知道问题出在哪里,只需创建一个扩展java.io.InputStream类的简单类,并通过将该类作为基础InputStream来创建一个ObjectInputStream。你会看到当一个ObjectInputStream类创建时,它会尝试读取 4 个字节作为头字节!所以这意味着你丢失了一些数据,这就是你的线程卡住的原因!如果你有反编译器,你也可以检查 ObjectInputStream 的代码。
推荐阅读
- c# - 使用同一个 UdpClient 在两个单独的线程上同时发送和接收 udp 数据报是否安全?
- asp.net - UpdatePanel 中的 ASP.NET 控件在文件上传后不起作用
- python - 如何将用户定义类的实例转换为元组
- c# - 如何在编辑时重新加载datagridview
- django - Django 库存应用工具购物车更新视图
- python - 在 plot.ly 中绘制股票数据
- sql-server - 授予对特定用户 Web API 2 的访问权限
- java - 如何防止 Java XSL 转换器插入命名空间前缀?
- python-3.x - Python 3.7.0 和 tcl/tk 8.6 在 Mac OS X 10.12.6 上崩溃
- python-2.7 - Python Sqlite3 attaching to a memory database