You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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;
            }
        }
    }
}

关键细节说明

  1. 线程安全集合:使用Collections.synchronizedList来存储客户端线程,避免多个线程同时操作集合时出现并发问题,同时在遍历集合时加锁synchronized (Main.clientThreads),进一步保障安全。
  2. 角色分配:在客户端连接时发送红方/黑方的角色信息,方便客户端初始化棋盘状态。
  3. 消息转发逻辑:收到客户端消息后,遍历线程列表,排除当前线程,将消息发送给另一个客户端,这样对方就能收到走棋指令并更新棋盘。
  4. 断开清理:无论是正常QUIT还是异常断开,都从集合中移除当前线程,避免无效引用。

这样修改后,你的服务器就能实现两个客户端之间的消息互通,接下来你只需要在客户端解析收到的走棋指令,更新本地棋盘即可。

内容的提问来源于stack exchange,提问作者Maihoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 15:57:35