Java多人桌游:Client2发消息时BufferedReader阻塞无响应
问题:双客户端连接后服务器无法获取第二客户端的移动指令
当2个客户端连接服务器后游戏自动启动,服务器先等待Client1输入,回合切换后进入等待Client2输入的状态,但此时服务器无法获取Client2发送的移动指令。
服务器端代码片段
private ServerSocket socket; private ServerTUI view; private ServerLogic serverLogic; private int readyCounter; private final List<ClientHandler> clients = new ArrayList<ClientHandler>(); private boolean madeMove = false; private int next_client_no; public Server() { view = new ServerTUI(); next_client_no = 1; readyCounter=0; } public void run() { boolean openNewSocket = true; while (openNewSocket) { try { setup(); while (true) { Socket sock = socket.accept(); ClientHandler handler = new ClientHandler(sock, this); synchronized (clients) { clients.add(handler); } new Thread(handler).start(); String name = "Client " + String.format("%02d", next_client_no++); view.showMessage("New client [" + name + "] connected!"); } } catch (Exception e) { openNewSocket = false; } } } public synchronized void playGame() throws ServerUnavailableException, IOException { Player current = null; while (!serverLogic.isGameOver(serverLogic.getPlayers().get(serverLogic.getCurrentPlayer()).getRack())) { madeMove = false; current = serverLogic.getPlayers().get(serverLogic.getCurrentPlayer()); getServerLogic().setCopyRack(current.getRack()); getServerLogic().setCopyBoard(getServerLogic().getBoard()); // 等待输入 while (!madeMove) { } changeTurn(); } }
服务器端ClientHandler代码
public class ClientHandler implements Runnable{ private BufferedReader in; private BufferedWriter out; private Socket sock; private Player player; private Server srv; private String name; public ClientHandler(Socket sock, Server srv){ try { this.sock = sock; this.srv = srv; in = new BufferedReader(new InputStreamReader(sock.getInputStream())); out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream())); } catch (IOException e) { shutdown(); } } public void run() { try { String msg; while ((msg = in.readLine()) != null) { // 此处似乎卡住 handleCommand(msg); // 从这里处理指令 } shutdown(); } catch (IOException | ServerUnavailableException e) { shutdown(); } } public synchronized void sendMessage(String message) throws ServerUnavailableException { if (out != null) { try { out.write(message); out.newLine(); out.flush(); } catch (IOException e) { throw new ServerUnavailableException("无法向客户端发送消息: " + e.getMessage()); } } } }
客户端代码片段
public class Client implements Runnable { @Override public void run() { try { String command; while (serverSock.isConnected()) { command = in.readLine(); processCommand(command); } } catch (IOException | ProtocolException e) { throw new RuntimeException(e); } } public void startClient() { startConnection(); } public void startConnection() { // 待实现 boolean connected = false; while (!connected) { try { createConnection(); name = view.getString("请输入用户名"); if (Protocol.isValidName(name)) { handleHello(); } else { System.out.println("请输入合法的用户名"); break; } connected = true; Thread listenerThread = new Thread(this); listenerThread.start(); } catch (ExitProgram e) { view.showMessage("正在退出程序..."); break; } catch (ServerUnavailableException e) { view.showMessage("连接失败: " + e.getMessage()); if (!view.getBoolean("是否重试?")) { break; } } catch (ProtocolException e) { throw new RuntimeException(e); } } } public synchronized void sendMessage(String msg) throws ServerUnavailableException { if (out != null) { try { out.write(msg); out.newLine(); out.flush(); } catch (IOException e) { view.showMessage(e.getMessage()); throw new ServerUnavailableException("无法向服务器写入消息: " + msg); } } else { throw new ServerUnavailableException("无法向服务器写入消息: " + msg); } } }
已尝试的解决方法
- 逐步调试,但多线程和双客户端环境下存在异常行为
- 将sendMessage独立为单独类,多种方案均未解决问题
内容的提问来源于stack exchange,提问作者efr hgfdshg
相关产品推荐
相关产品推荐

