如何实现Java国际象棋服务器Socket线程间通信,完成客户端消息交互?
解决Java象棋服务器客户端间消息转发问题
嘿,很高兴看到你第一次做服务器开发就走到这一步了!目前你已经搞定了双客户端连接和回显,接下来要实现的客户端之间的消息转发,正是象棋这类对战应用的核心环节。我来给你拆解下具体的实现思路和修改方案:
核心思路
要实现两个客户端的通信,关键在于让服务器能找到所有已连接的客户端线程,并在收到一个客户端的消息时,将其转发给另一个客户端。我们可以通过以下几步来实现:
- 在主类中维护所有客户端线程的引用
- 给客户端线程添加发送消息的方法
- 收到消息时遍历线程列表,转发给其他客户端
- 处理客户端断开时的线程清理
修改后的完整代码
Main类修改版
package Main; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.Collections; import java.util.List; import TCP.TCPServerThread; public class Main { public static final String StopCode = "STOP"; public static final int PORT = 8888; public static int count = 0; // 用线程安全的集合存储客户端线程,避免多线程操作问题 public static List<TCPServerThread> clientThreads = Collections.synchronizedList(new ArrayList<>()); public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; // 创建Server Socket try { serverSocket = new ServerSocket(PORT); } catch (IOException e) { e.printStackTrace(); } System.out.println("serverSocket created"); // 接受客户端连接,最多2个 while (count < 2) { try { socket = serverSocket.accept(); count++; System.out.println("socket Nr " + count + " accepted"); // 创建并保存客户端线程 TCPServerThread clientThread = new TCPServerThread(socket); clientThreads.add(clientThread); clientThread.start(); // 给客户端分配角色(红方/黑方) clientThread.sendMessage("你是" + (count == 1 ? "红方" : "黑方") + ",等待对方走棋..."); } catch (IOException e) { System.out.println("I/O error: " + e); } } } }
TCPServerThread类修改版
package TCP; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; import java.sql.Timestamp; import Main.Main; public class TCPServerThread extends Thread{ Timestamp ts; private int port = 0uses;status(强)建议 送法 valued输出�Ke的 //A Socket socket; // 将输出流提升为类成员,方便sendMessage方法访问 private DataOutputStream os; public TCPServerThread(Socket clientSocket) { this.socket = clientSocket; } // 新增发送消息的方法 public void sendMessage(String message) { try { if (os != null) { os.writeBytes(message + "\n\r"); os.flush(); } } catch (IOException e) { e.printStackTrace(); } } public void run() { InputStream is = null; BufferedReader br = null; try { is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); os = new DataOutputStream(socket.getOutputStream()); } catch (IOException e) { e.printStackTrace(); return; } String line; while (true) { try { line = br.readLine(); if ((line == null) || line.equalsIgnoreCase("QUIT")) { // 客户端断开时,从集合中移除当前线程 Main.clientThreads.remove(this); socket.close(); System.out.println("客户端断开连接"); return; } else { // 转发消息给另一个客户端 synchronized (Main.clientThreads) { // 加锁保证线程安全 for (TCPServerThread thread : Main.clientThreads) { if (thread != this) { thread.sendMessage("对方走棋:" + line); } } } // 回显给当前客户端,确认消息已发送 os.writeBytes("已发送走棋指令:" + line + "\n\r"); os.flush(); } } catch (IOException e) { e.printStackTrace(); // 异常断开时也要清理线程 Main.clientThreads.remove(this); return; } } } }
关键细节说明
- 线程安全集合:使用
Collections.synchronizedList来存储客户端线程,避免多个线程同时操作集合时出现并发问题,同时在遍历集合时加锁synchronized (Main.clientThreads),进一步保障安全。 - 角色分配:在客户端连接时发送红方/黑方的角色信息,方便客户端初始化棋盘状态。
- 消息转发逻辑:收到客户端消息后,遍历线程列表,排除当前线程,将消息发送给另一个客户端,这样对方就能收到走棋指令并更新棋盘。
- 断开清理:无论是正常QUIT还是异常断开,都从集合中移除当前线程,避免无效引用。
这样修改后,你的服务器就能实现两个客户端之间的消息互通,接下来你只需要在客户端解析收到的走棋指令,更新本地棋盘即可。
内容的提问来源于stack exchange,提问作者Maihoo
相关产品推荐
相关产品推荐

