最新资讯

  • 多内网服务器公网中转通信方案(Spring Boot 2.7 + MyBatis Plus)

多内网服务器公网中转通信方案(Spring Boot 2.7 + MyBatis Plus)

2026-01-28 18:01:48 栏目:最新资讯 1 阅读

多内网服务器公网中转通信方案(Spring Boot 2.7 + MyBatis Plus)

一、整体架构说明

  1. 核心架构:采用「公网中转服务端 + 内网客户端(A/B/…)」的TCP Socket架构,公网服务器作为消息转发枢纽,内网客户端通过该枢纽实现相互通信
  2. 关键约束:内网客户端不直连公网MySQL,仅操作本地MySQL(通过MyBatis Plus)
  3. 核心特性:支持自动重连、消息确认(防丢失)、心跳检测(保连接)、多客户端扩展、实时请求响应
  4. 消息流转:客户端A→公网中转→客户端B(B实时处理)→公网中转→客户端A

二、统一依赖(服务端 + 客户端)


<dependencies>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starterartifactId>
        <version>2.7.18version>
    dependency>

    
    <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>fastjsonartifactId>
        <version>2.0.25version>
    dependency>

    
    <dependency>
        <groupId>com.baomidougroupId>
        <artifactId>mybatis-plus-boot-starterartifactId>
        <version>3.5.3version>
    dependency>

    
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>8.0.30version>
        <scope>runtimescope>
    dependency>

    
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <optional>trueoptional>
    dependency>
dependencies>

三、通用核心组件(服务端 + 客户端共用)

1. 自定义消息实体(统一消息格式)

import lombok.Data;
import java.util.Date;

/**
 * 统一消息体(用于传输、本地存储)
 */
@Data
public class Message {
    /** 唯一消息ID(用于消息确认) */
    private String msgId;
    /** 发送方客户端标识(如client_a、client_b) */
    private String sender;
    /** 接收方客户端标识(如client_b、client_a,广播可填all) */
    private String receiver;
    /** 消息类型:REQUEST(请求)、RESPONSE(响应)、HEARTBEAT(心跳)、ACK(确认) */
    private String msgType;
    /** 消息内容(自定义JSON字符串) */
    private String content;
    /** 发送时间 */
    private Date sendTime;
    /** 确认ID(关联待确认的消息ID) */
    private String ackMsgId;
    /** 消息状态:SEND(已发送)、ACKED(已确认)、PROCESSED(已处理) */
    private String status;
}

2. 本地消息记录表(MySQL,内网客户端本地创建)

-- 本地消息记录表(每个内网客户端本地数据库执行)
CREATE TABLE `local_message` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `msg_id` varchar(64) NOT NULL COMMENT '消息唯一标识',
  `sender` varchar(32) NOT NULL COMMENT '发送方',
  `receiver` varchar(32) NOT NULL COMMENT '接收方',
  `msg_type` varchar(16) NOT NULL COMMENT '消息类型',
  `content` text COMMENT '消息内容',
  `send_time` datetime NOT NULL COMMENT '发送时间',
  `ack_msg_id` varchar(64) DEFAULT NULL COMMENT '确认消息ID',
  `status` varchar(16) NOT NULL COMMENT '消息状态',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_msg_id` (`msg_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='本地消息存储表';

3. MyBatis Plus 基础配置

(1)Message实体对应的Mapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

/**
 * 本地消息Mapper(内网客户端)
 */
@Mapper
public interface LocalMessageMapper extends BaseMapper<LocalMessage> {
    // 继承BaseMapper,无需额外编写CRUD方法
}
(2)LocalMessage 实体(对应数据库表)
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;

@Data
@TableName("local_message")
public class LocalMessage {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String msgId;
    private String sender;
    private String receiver;
    private String msgType;
    private String content;
    private Date sendTime;
    private String ackMsgId;
    private String status;
    private Date createTime;
    private Date updateTime;
}

四、公网中转服务端(核心:消息转发 + 连接管理)

1. 服务端配置(application.yml)

server:
  port: 8080 # Spring Boot 端口
socket:
  port: 8888 # Socket 监听端口(内网客户端连接端口)
  heartbeat-timeout: 30000 # 心跳超时时间(30秒,超过则断开连接)

2. 核心服务端代码(SocketServer)

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 公网中转Socket服务端(负责连接管理、消息转发、心跳检测)
 */
@Slf4j
@Component
public class SocketTransferServer implements ApplicationRunner {
    @Value("${socket.port}")
    private int socketPort;
    @Value("${socket.heartbeat-timeout}")
    private long heartbeatTimeout;

    // 客户端连接池:key=客户端标识,value=Socket连接(线程安全,支持多客户端)
    private static final Map<String, SocketClientHolder> CLIENT_MAP = new ConcurrentHashMap<>();
    // 定时任务池(心跳检测)
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    /**
     * Spring Boot启动后,启动Socket服务端
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 启动心跳检测任务(每10秒检测一次)
        scheduler.scheduleAtFixedRate(this::checkHeartbeat, 10, 10, TimeUnit.SECONDS);

        // 启动Socket服务端监听
        try (ServerSocket serverSocket = new ServerSocket(socketPort)) {
            log.info("公网中转服务端启动成功,监听端口:{}", socketPort);
            while (true) {
                // 阻塞等待客户端连接
                Socket clientSocket = serverSocket.accept();
                log.info("新客户端连接:{}", clientSocket.getInetAddress().getHostAddress());
                // 启动独立线程处理客户端消息
                new Thread(() -> handleClient(clientSocket)).start();
            }
        } catch (IOException e) {
            log.error("Socket服务端启动失败", e);
        }
    }

    /**
     * 处理单个客户端的消息读取与转发
     */
    private void handleClient(Socket clientSocket) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8));
            String jsonStr;
            // 持续读取客户端消息
            while ((jsonStr = reader.readLine()) != null) {
                Message message = JSON.parseObject(jsonStr, Message.class);
                log.info("收到客户端消息:{}", jsonStr);

                // 1. 心跳消息:更新客户端最后活跃时间
                if ("HEARTBEAT".equals(message.getMsgType())) {
                    SocketClientHolder holder = CLIENT_MAP.get(message.getSender());
                    if (holder != null) {
                        holder.setLastActiveTime(System.currentTimeMillis());
                    }
                    continue;
                }

                // 2. 首次连接:注册客户端标识
                if (!CLIENT_MAP.containsKey(message.getSender())) {
                    CLIENT_MAP.put(message.getSender(), new SocketClientHolder(clientSocket, System.currentTimeMillis()));
                    log.info("客户端注册成功:{}", message.getSender());
                }

                // 3. 普通消息(REQUEST/RESPONSE/ACK):转发给目标客户端
                SocketClientHolder targetHolder = CLIENT_MAP.get(message.getReceiver());
                if (targetHolder != null) {
                    OutputStreamWriter writer = new OutputStreamWriter(targetHolder.getSocket().getOutputStream(), StandardCharsets.UTF_8);
                    writer.write(jsonStr + "
");
                    writer.flush();
                    log.info("消息转发成功:{} -> {}", message.getSender(), message.getReceiver());
                } else {
                    log.warn("目标客户端未在线:{}", message.getReceiver());
                }
            }
        } catch (IOException e) {
            log.error("客户端连接异常", e);
        } finally {
            // 移除失效连接
            CLIENT_MAP.entrySet().removeIf(entry -> entry.getValue().getSocket() == clientSocket);
            try {
                if (reader != null) reader.close();
                clientSocket.close();
            } catch (IOException e) {
                log.error("关闭客户端连接失败", e);
            }
            log.info("客户端连接断开:{}", clientSocket.getInetAddress().getHostAddress());
        }
    }

    /**
     * 心跳检测:移除超时未活跃的客户端
     */
    private void checkHeartbeat() {
        long currentTime = System.currentTimeMillis();
        CLIENT_MAP.entrySet().removeIf(entry -> {
            long idleTime = currentTime - entry.getValue().getLastActiveTime();
            boolean timeout = idleTime > heartbeatTimeout;
            if (timeout) {
                log.warn("客户端心跳超时,移除连接:{}", entry.getKey());
                try {
                    entry.getValue().getSocket().close();
                } catch (IOException e) {
                    log.error("关闭超时客户端连接失败", e);
                }
            }
            return timeout;
        });
    }

    /**
     * 客户端连接持有者(存储Socket + 最后活跃时间)
     */
    static class SocketClientHolder {
        private Socket socket;
        private long lastActiveTime;

        public SocketClientHolder(Socket socket, long lastActiveTime) {
            this.socket = socket;
            this.lastActiveTime = lastActiveTime;
        }

        // getter/setter 省略(可通过lombok生成)
        public Socket getSocket() { return socket; }
        public void setSocket(Socket socket) { this.socket = socket; }
        public long getLastActiveTime() { return lastActiveTime; }
        public void setLastActiveTime(long lastActiveTime) { this.lastActiveTime = lastActiveTime; }
    }
}

五、内网客户端(A/B通用,仅修改配置标识)

1. 客户端配置(application.yml)

# 客户端唯一标识(client_a / client_b / client_c ...)
client:
  id: client_a
# 公网中转服务端配置
socket:
  server-ip: 1.2.3.4 # 公网服务器IP
  server-port: 8888 # 公网Socket端口
  reconnect-interval: 5000 # 重连间隔(5秒)
  heartbeat-interval: 10000 # 心跳发送间隔(10秒)
  msg-timeout: 20000 # 消息超时时间(20秒,未确认则重发)
  retry-count: 3 # 消息重发次数
# 本地MySQL配置(内网客户端本地数据库)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/local_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2. 核心客户端代码(SocketClient + 自动重连 + 心跳 + 消息确认)

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 内网客户端(A/B通用):自动重连 + 心跳 + 消息确认 + 实时消息处理
 */
@Slf4j
@Component
public class InnerSocketClient implements ApplicationRunner {
    @Value("${client.id}")
    private String clientId;
    @Value("${socket.server-ip}")
    private String serverIp;
    @Value("${socket.server-port}")
    private int serverPort;
    @Value("${socket.reconnect-interval}")
    private long reconnectInterval;
    @Value("${socket.heartbeat-interval}")
    private long heartbeatInterval;
    @Value("${socket.msg-timeout}")
    private long msgTimeout;
    @Value("${socket.retry-count}")
    private int retryCount;

    @Autowired
    private LocalMessageMapper localMessageMapper;

    // Socket连接
    private volatile Socket socket;
    // 待确认消息池:key=消息ID,value=消息详情(含重发次数)
    private final Map<String, PendingMsg> PENDING_MSG_MAP = new ConcurrentHashMap<>();
    // 定时任务池(重连 + 心跳 + 消息超时检测)
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
    // 消息发送锁(保证线程安全)
    private final Object sendLock = new Object();

    /**
     * Spring Boot启动后,初始化客户端
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 1. 启动自动重连任务
        scheduler.scheduleAtFixedRate(this::reconnect, 0, reconnectInterval, TimeUnit.MILLISECONDS);
        // 2. 启动心跳发送任务
        scheduler.scheduleAtFixedRate(this::sendHeartbeat, heartbeatInterval, heartbeatInterval, TimeUnit.MILLISECONDS);
        // 3. 启动消息超时检测任务(重发超时未确认消息)
        scheduler.scheduleAtFixedRate(this::checkMsgTimeout, 5, 5, TimeUnit.SECONDS);
    }

    /**
     * 自动重连:连接断开时自动重试
     */
    private void reconnect() {
        if (socket != null && socket.isConnected() && !socket.isClosed()) {
            return;
        }
        try {
            log.info("尝试连接公网服务端:{}:{}", serverIp, serverPort);
            Socket newSocket = new Socket(serverIp, serverPort);
            this.socket = newSocket;
            log.info("公网服务端连接成功!");
            // 连接成功后,发送注册消息(携带客户端标识)
            sendRegisterMsg();
            // 启动消息监听线程(实时接收消息)
            new Thread(this::listenMsg).start();
        } catch (IOException e) {
            log.error("连接公网服务端失败,{}毫秒后重试", reconnectInterval, e);
        }
    }

    /**
     * 发送注册消息(首次连接时)
     */
    private void sendRegisterMsg() {
        Message msg = new Message();
        msg.setMsgId(UUID.randomUUID().toString());
        msg.setSender(clientId);
        msg.setReceiver("server");
        msg.setMsgType("REGISTER");
        msg.setSendTime(new Date());
        msg.setStatus("SEND");
        sendMsg(msg);
    }

    /**
     * 发送心跳消息
     */
    private void sendHeartbeat() {
        if (socket == null || socket.isClosed()) {
            return;
        }
        Message msg = new Message();
        msg.setMsgId(UUID.randomUUID().toString());
        msg.setSender(clientId);
        msg.setReceiver("server");
        msg.setMsgType("HEARTBEAT");
        msg.setSendTime(new Date());
        msg.setStatus("SEND");
        sendMsg(msg);
    }

    /**
     * 发送自定义消息(对外提供的核心方法)
     * @param receiver 目标客户端标识(如client_b)
     * @param content  自定义消息内容
     * @return 消息ID
     */
    public String sendCustomMsg(String receiver, String content) {
        Message msg = new Message();
        String msgId = UUID.randomUUID().toString();
        msg.setMsgId(msgId);
        msg.setSender(clientId);
        msg.setReceiver(receiver);
        msg.setMsgType("REQUEST");
        msg.setContent(content);
        msg.setSendTime(new Date());
        msg.setStatus("SEND");
        // 1. 保存到本地数据库
        saveLocalMsg(msg);
        // 2. 发送消息并加入待确认池
        sendMsg(msg);
        PENDING_MSG_MAP.put(msgId, new PendingMsg(msg, 0, System.currentTimeMillis()));
        return msgId;
    }

    /**
     * 底层消息发送实现
     */
    private void sendMsg(Message msg) {
        synchronized (sendLock) {
            if (socket == null || socket.isClosed()) {
                log.error("Socket连接未建立,消息发送失败:{}", JSON.toJSONString(msg));
                return;
            }
            try {
                OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8);
                writer.write(JSON.toJSONString(msg) + "
");
                writer.flush();
                log.info("消息发送成功:{}", JSON.toJSONString(msg));
            } catch (IOException e) {
                log.error("消息发送失败,触发重连", e);
                // 发送失败,关闭Socket触发重连
                closeSocket();
            }
        }
    }

    /**
     * 实时监听公网服务端转发的消息
     */
    private void listenMsg() {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
            String jsonStr;
            // 持续监听消息(实时处理)
            while ((jsonStr = reader.readLine()) != null) {
                Message msg = JSON.parseObject(jsonStr, Message.class);
                log.info("收到转发消息:{}", jsonStr);
                // 1. 消息确认:移除待确认池并更新本地消息状态
                if ("ACK".equals(msg.getMsgType())) {
                    PENDING_MSG_MAP.remove(msg.getAckMsgId());
                    updateLocalMsgStatus(msg.getAckMsgId(), "ACKED");
                    continue;
                }
                // 2. 响应消息:业务处理(可自定义)
                if ("RESPONSE".equals(msg.getMsgType())) {
                    handleResponseMsg(msg);
                    // 发送确认消息
                    sendAckMsg(msg.getMsgId(), msg.getSender());
                    continue;
                }
                // 3. 请求消息:实时处理并返回响应
                if ("REQUEST".equals(msg.getMsgType())) {
                    handleRequestMsg(msg);
                    continue;
                }
            }
        } catch (IOException e) {
            log.error("消息监听异常,触发重连", e);
            closeSocket();
        } finally {
            try {
                if (reader != null) reader.close();
            } catch (IOException e) {
                log.error("关闭输入流失败", e);
            }
        }
    }

    /**
     * 处理请求消息(实时业务处理,可自定义)
     */
    private void handleRequestMsg(Message requestMsg) {
        try {
            // 1. 先发送确认消息(防止消息丢失)
            sendAckMsg(requestMsg.getMsgId(), requestMsg.getSender());
            // 2. 实时处理业务逻辑(此处为示例,可自定义)
            log.info("实时处理请求消息:{}", requestMsg.getContent());
            String responseContent = "处理完成:" + requestMsg.getContent() + "(来自" + clientId + ")";
            // 3. 发送响应消息
            Message responseMsg = new Message();
            responseMsg.setMsgId(UUID.randomUUID().toString());
            responseMsg.setSender(clientId);
            responseMsg.setReceiver(requestMsg.getSender());
            responseMsg.setMsgType("RESPONSE");
            responseMsg.setContent(responseContent);
            responseMsg.setSendTime(new Date());
            responseMsg.setStatus("SEND");
            // 保存响应消息到本地
            saveLocalMsg(responseMsg);
            // 发送响应消息
            sendMsg(responseMsg);
            // 更新请求消息本地状态
            updateLocalMsgStatus(requestMsg.getMsgId(), "PROCESSED");
        } catch (Exception e) {
            log.error("处理请求消息失败", e);
        }
    }

    /**
     * 处理响应消息(可自定义业务逻辑)
     */
    private void handleResponseMsg(Message responseMsg) {
        log.info("收到响应消息:{} -> {},内容:{}",
                responseMsg.getSender(), clientId, responseMsg.getContent());
        // 业务处理:如更新业务状态、通知上层服务等
        updateLocalMsgStatus(responseMsg.getMsgId(), "PROCESSED");
    }

    /**
     * 发送消息确认(ACK)
     */
    private void sendAckMsg(String ackMsgId, String receiver) {
        Message ackMsg = new Message();
        ackMsg.setMsgId(UUID.randomUUID().toString());
        ackMsg.setSender(clientId);
        ackMsg.setReceiver(receiver);
        ackMsg.setMsgType("ACK");
        ackMsg.setAckMsgId(ackMsgId);
        ackMsg.setSendTime(new Date());
        ackMsg.setStatus("SEND");
        sendMsg(ackMsg);
    }

    /**
     * 检查消息超时:重发超时未确认的消息
     */
    private void checkMsgTimeout() {
        long currentTime = System.currentTimeMillis();
        PENDING_MSG_MAP.entrySet().forEach(entry -> {
            PendingMsg pendingMsg = entry.getValue();
            // 超时判断
            if (currentTime - pendingMsg.getSendTime() > msgTimeout) {
                // 重发次数判断
                if (pendingMsg.getRetryCount() < retryCount) {
                    log.info("消息超时,开始重发(第{}次):{}",
                            pendingMsg.getRetryCount() + 1, entry.getKey());
                    // 重发消息
                    sendMsg(pendingMsg.getMessage());
                    // 更新重发次数和发送时间
                    pendingMsg.setRetryCount(pendingMsg.getRetryCount() + 1);
                    pendingMsg.setSendTime(System.currentTimeMillis());
                } else {
                    log.error("消息重发次数耗尽,发送失败:{}", entry.getKey());
                    // 移除待确认池,更新本地状态
                    PENDING_MSG_MAP.remove(entry.getKey());
                    updateLocalMsgStatus(entry.getKey(), "FAILED");
                }
            }
        });
    }

    /**
     * 保存消息到本地数据库
     */
    private void saveLocalMsg(Message msg) {
        LocalMessage localMessage = new LocalMessage();
        localMessage.setMsgId(msg.getMsgId());
        localMessage.setSender(msg.getSender());
        localMessage.setReceiver(msg.getReceiver());
        localMessage.setMsgType(msg.getMsgType());
        localMessage.setContent(msg.getContent());
        localMessage.setSendTime(msg.getSendTime());
        localMessage.setAckMsgId(msg.getAckMsgId());
        localMessage.setStatus(msg.getStatus());
        localMessageMapper.insert(localMessage);
    }

    /**
     * 更新本地消息状态
     */
    private void updateLocalMsgStatus(String msgId, String status) {
        LambdaUpdateWrapper<LocalMessage> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(LocalMessage::getMsgId, msgId)
                     .set(LocalMessage::getStatus, status);
        localMessageMapper.update(null, updateWrapper);
    }

    /**
     * 关闭Socket连接
     */
    private void closeSocket() {
        if (socket != null && !socket.isClosed()) {
            try {
                socket.close();
            } catch (IOException e) {
                log.error("关闭Socket失败", e);
            }
        }
    }

    /**
     * 待确认消息持有者
     */
    static class PendingMsg {
        private Message message;
        private int retryCount;
        private long sendTime;

        public PendingMsg(Message message, int retryCount, long sendTime) {
            this.message = message;
            this.retryCount = retryCount;
            this.sendTime = sendTime;
        }

        // getter/setter 省略
        public Message getMessage() { return message; }
        public void setMessage(Message message) { this.message = message; }
        public int getRetryCount() { return retryCount; }
        public void setRetryCount(int retryCount) { this.retryCount = retryCount; }
        public long getSendTime() { return sendTime; }
        public void setSendTime(long sendTime) { this.sendTime = sendTime; }
    }
}

3. 客户端测试代码(发送消息示例)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

/**
 * 客户端测试:启动后发送测试消息
 */
@Component
public class ClientTestRunner implements CommandLineRunner {
    @Autowired
    private InnerSocketClient innerSocketClient;

    @Override
    public void run(String... args) throws Exception {
        // 延迟5秒(确保连接建立成功)
        Thread.sleep(5000);
        // 发送测试消息给client_b(客户端A配置)
        // 若为客户端B,可发送给client_a
        String msgId = innerSocketClient.sendCustomMsg("client_b", "这是来自client_a的测试请求");
        log.info("发送测试消息,消息ID:{}", msgId);
    }
}

六、核心特性说明

  1. 多客户端扩展:仅需修改application.yml中的client.id(如client_c、client_d),即可实现无限扩展
  2. 自动重连:客户端检测到Socket断开(发送/监听异常),会每隔5秒自动重试连接,直到成功
  3. 消息确认:发送方发送消息后加入待确认池,接收方收到消息后立即返回ACK,发送方超时未收到则自动重发(最多3次)
  4. 心跳检测:客户端每10秒发送心跳,服务端30秒未收到心跳则移除连接,客户端检测到连接异常则触发重连
  5. 实时处理:客户端启动独立线程持续监听消息,收到请求后立即处理并返回响应,无延迟
  6. 消息持久化:所有消息均保存到内网客户端本地MySQL(通过MyBatis Plus),可追溯、防丢失

七、部署与使用步骤

  1. 公网服务器部署:启动公网中转服务端(Spring Boot项目)
  2. 内网客户端A部署:
    • 本地创建MySQL数据库并执行local_message表SQL
    • 修改application.ymlclient.id=client_a、公网IP、本地MySQL配置
    • 启动客户端A
  3. 内网客户端B部署:
    • 本地创建MySQL数据库并执行local_message表SQL
    • 修改application.ymlclient.id=client_b、公网IP、本地MySQL配置
    • 启动客户端B
  4. 自动通信:客户端A可发送消息给client_b,客户端B实时处理并返回响应,反之亦然

本文地址:https://www.yitenyun.com/534.html

搜索文章

Tags

#ios面试 #ios弱网 #断点续传 #ios开发 #objective-c #ios #ios缓存 #服务器 #python #pip #conda #远程工作 香港站群服务器 多IP服务器 香港站群 站群服务器 #kubernetes #笔记 #平面 #容器 #linux #学习方法 #运维 #fastapi #html #css #进程控制 #cpolar #低代码 #爬虫 #音视频 #docker #后端 #数据库 #Trae #IDE #AI 原生集成开发环境 #Trae AI #开发语言 #云原生 #iventoy #VmWare #OpenEuler #人工智能 #node.js #Conda # 私有索引 # 包管理 #内网穿透 #网络 #RTP over RTSP #RTP over TCP #RTSP服务器 #RTP #TCP发送RTP #MobaXterm #ubuntu #开源 #android #腾讯云 #c# #kylin #物联网 #websocket #vscode #mobaxterm #深度学习 #计算机视觉 #tcp/ip #多个客户端访问 #IO多路复用 #回显服务器 #TCP相关API #学习 #web安全 #安全 #算法 #大数据 #数信院生信服务器 #Rstudio #生信入门 #生信云服务器 #nginx #华为 #ModelEngine #架构 #mvp #个人开发 #设计模式 #java #claude #金融 #大模型 #mcp #金融投资Agent #Agent #windows #我的世界 #github #git #ssh #n8n #本地部署 #云计算 #hadoop #hbase #hive #zookeeper #spark #kafka #flink #qt #C++ #udp #c++ #c语言 #网络协议 #我的世界服务器搭建 #minecraft #jar #面试 #ide #AI编程 #pycharm #单元测试 #集成测试 #NPU #CANN #DisM++ # GLM-4.6V # 系统维护 #京东云 #性能优化 #gpu算力 #vue.js #前端 #vue #阿里云 #JumpServer #堡垒机 #振镜 #振镜焊接 #unity3d #游戏 #服务器框架 #Fantasy #YOLOFuse # Base64编码 # 多模态检测 #SRS #流媒体 #直播 #http #守护进程 #复用 #screen #Android #Bluedroid #智能手机 #umeditor粘贴word #ueditor粘贴word #ueditor复制word #ueditor上传word图片 #缓存 #MCP #科技 #自然语言处理 #神经网络 #压力测试 #mamba #libosinfo #jenkins #需求分析 #scala #测试用例 #测试工具 #Dell #PowerEdge620 #内存 #硬盘 #RAID5 #todesk #cpp #项目 #高并发 #unity #游戏引擎 #gemini #gemini国内访问 #gemini api #gemini中转搭建 #Cloudflare #screen 命令 #stm32 #macos #MCP服务器 #银河麒麟 #系统升级 #信创 #国产化 #东方仙盟 #嵌入式硬件 #flask #GPU服务器 #8U #硬件架构 #编辑器 #SAP #ebs #metaerp #oracle ebs #智能路由器 #DeepSeek #蓝耘智算 #5G #910B #昇腾 #AIGC #ida #ai #搜索引擎 #Anaconda配置云虚拟环境 #C2000 #TI #实时控制MCU #AI服务器电源 #pytorch #密码学 #可信计算技术 #1024程序员节 #华为云 #测评 #CCE #Dify-LLM #Flexus #cursor #elasticsearch #ollama #llm #django #web3.py #centos #RustDesk #IndexTTS 2.0 #本地化部署 #麒麟OS #信息与通信 #信号处理 #tcpdump #毕业设计 #车辆排放 #ms-swift # 大模型 # 模型训练 #Nacos #web #微服务 #transformer #javascript #银河麒麟高级服务器操作系统安装 #银河麒麟高级服务器V11配置 #设置基础软件仓库时出错 #银河麒高级服务器系统的实操教程 #生产级部署银河麒麟服务系统教程 #Linux系统的快速上手教程 #AI #工具集 #sqlite #epoll #oracle #php #电气工程 #C# #PLC #单片机 #golang #rdp #SSH反向隧道 # Miniconda # Jupyter远程访问 #自动化 #maven #gitlab #课程设计 #spring boot #PyTorch # Triton # 高并发部署 #chatgpt #codex #yum #三维 #3D #三维重建 #java-ee #mysql #sql #万悟 #联通元景 #智能体 #镜像 #微信小程序 #小程序 #微信 #健身房预约系统 #健身房管理系统 #健身管理系统 #Dify #ARM架构 #鲲鹏 #react.js #jmeter #功能测试 #软件测试 #自动化测试 #职场和发展 #EMC存储 #存储维护 #NetApp存储 #apache #鸭科夫 #逃离鸭科夫 #鸭科夫联机 #鸭科夫异地联机 #开服 #北京百思可瑞教育 #百思可瑞教育 #北京百思教育 #NAS #Termux #Samba #Linux #deepseek #risc-v #fiddler #部署 #debian #运维开发 #API限流 # 频率限制 # 令牌桶算法 #驱动开发 #iBMC #UltraISO #黑群晖 #虚拟机 #无U盘 #纯小白 #支付 #聊天小程序 #SSH跳板机 # Python3.11 #心理健康服务平台 #心理健康系统 #心理服务平台 #心理健康小程序 #fpga开发 #LVDS #高速ADC #DDR #蓝湖 #Axure原型发布 #nodejs #screen命令 #Gunicorn #WSGI #Flask #并发模型 #容器化 #Python #性能调优 #asp.net #练习 #基础练习 #数组 #循环 #九九乘法表 #计算机实现 #管道Pipe #system V #ai编程 #dynadot #域名 #网络安全 #机器人 #esb接口 #走处理类报异常 #bug菌问答团队 #llama #opencv #语言模型 #YOLO #ffmpeg #数据分析 #数据挖掘 #交互 #门禁 #梯控 #智能一卡通 #门禁一卡通 #消费一卡通 #智能梯控 #一卡通 #源代码管理 #超时设置 #客户端/服务器 #网络编程 #uv #uvx #uv pip #npx #Ruff #pytest #银河麒麟部署 #银河麒麟部署文档 #银河麒麟linux #银河麒麟linux部署教程 #intellij-idea #idea #intellij idea #muduo库 #arm开发 #操作系统 #国产化OS #ui #react native #中间件 #MQTT协议 #C语言 #leetcode #vivado license #CVE-2025-68143 #CVE-2025-68144 #CVE-2025-68145 #html5 #AI 推理 #NV #SSH # 批量管理 #语音识别 #ASR #SenseVoice #星图GPU #证书 #fabric #postgresql #openHiTLS #TLCP #DTLCP #商用密码算法 #chrome #ONLYOFFICE #MCP 服务器 #处理器 #laravel #ssl #数据结构 #tomcat #prometheus #grafana #svn #毕设 #排序算法 #服务器繁忙 #serverless #RAID #RAID技术 #磁盘 #存储 #gitea #经验分享 #jvm # 双因素认证 # TensorFlow #adb # 目标检测 #连接数据库报错 #DNS #mybatis #YOLO26 #目标检测 #硬件工程 #智能家居 #pyqt #进程 #进程创建与终止 #shell #Spring AI #STDIO传输 #SSE传输 #WebMVC #WebFlux #redis #bootstrap #milvus #springboot #知识库 #企业微信 #SPA #单页应用 #web server #请求处理流程 #C #个人博客 #交通物流 #swagger #visual studio code #rocketmq #selenium #scrapy #mariadb #pve #wsl #LangGraph #CLI #JavaScript #langgraph.json #蓝牙 #LE Audio #BAP #嵌入式编译 #ccache #distcc #paddleocr #STDIO协议 #Streamable-HTTP #McpTool注解 #服务器能力 #分布式 #链表 #puppeteer #动态规划 #负载均衡 #xlwings #Excel #dlms #dlms协议 #逻辑设备 #逻辑设置间权限 #numpy #安全威胁分析 #仙盟创梦IDE #wordpress #雨云 #LobeChat #vLLM #GPU加速 #spring cloud #spring #nfs #iscsi #人脸识别sdk #视频编解码 #人脸识别 #海外服务器安装宝塔面板 #prompt #大模型学习 #翻译 #开源工具 #ansible #文件管理 #文件服务器 #树莓派4b安装系统 #langchain #大模型开发 #程序员 #大模型部署 #mindie #大模型推理 #创业创新 #业界资讯 #openlayers #bmap #tile #server #电脑 #简单数论 #埃氏筛法 #TCP #客户端 #嵌入式 #DIY机器人工房 #CosyVoice3 # 语音合成 #windows11 #microsoft #系统修复 #KMS激活 #计算机网络 #jdk #排序 #ddos #系统架构 #x86_64 #数字人系统 #数据仓库 #信令服务器 #Janus #MediaSoup #其他 #rtsp #转发 #CSDN #CVE-2025-61686 #漏洞 #路径遍历高危漏洞 #SQL注入主机 #webrtc #idm #ThingsBoard MCP # GPU租赁 # 自建服务器 #devops #戴尔服务器 #戴尔730 #装系统 #机器学习 #遛狗 #eBPF #Puppet # IndexTTS2 # TTS #bug #sqlserver #HeyGem # 服务器IP访问 # 端口映射 #说话人验证 #声纹识别 #CAM++ #unix # 一锤定音 # 大模型微调 #数据安全 #注入漏洞 #json #vllm #rust #CUDA #Triton #SSH公钥认证 # PyTorch # 安全加固 #大模型教程 #AI大模型 #结构体 #制造 #dify #ping通服务器 #读不了内网数据库 #企业开发 #ERP #项目实践 #.NET开发 #C#编程 #编程与数学 #昇腾300I DUO #Qwen3-14B # 大模型部署 # 私有化AI #vnstat #监控 #渗透测试 #黑客技术 #计算机 #文件上传漏洞 #mcu #推荐算法 #攻防演练 #Java web #红队 #A2A #GenAI #SSE # AI翻译机 # 实时翻译 #文心一言 #AI智能体 #vp9 #TTS私有化 # IndexTTS # 音色克隆 #无人机 #Deepoc #具身模型 #开发板 #未来 #word #IO #插件 #开源软件 #wireshark #网络安全大赛 #信息可视化 #指针 #anaconda #虚拟环境 #FHSS #GB28181 #SIP信令 #SpringBoot #视频监控 #WT-2026-0001 #QVD-2026-4572 #smartermail # GLM-TTS # 数据安全 #CNAS #CMA #程序文件 #xshell #host key #Emby #视频 #实时检测 #卷积神经网络 #ip #googlecloud #Modbus-TCP #DAG # ARM服务器 # 大模型推理 #云服务器选购 #Saas #CPU #线程 #VibeVoice #NFC #智能公交 #服务器计费 #FP-增长 #outlook #错误代码2603 #无网络连接 #2603 #系统管理 #服务 #挖矿 #Linux病毒 #dba #turn #网安应急响应 #ETL管道 #RAG #向量存储 #数据预处理 #DocumentReader #微PE # GLM # 服务连通性 #harmonyos #HarmonyOS APP #azure #ceph #ambari #arm #具身智能 #SSH密钥 # CUDA #数据可视化 #LLM # 高并发 #rtmp #数据恢复 #视频恢复 #视频修复 #RAID5恢复 #流媒体服务器恢复 #aws #哈希算法 #AI电商客服 #spring ai #oauth2 #Tokio #华为od #华为机试 #Java #cosmic #https #SSH跳转 # 高温监控 #TTS #go # GPU集群 #fs7TF #Gateway #认证服务器集成详解 #服务器开启 TLS v1.2 #IISCrypto 使用教程 #TLS 协议配置 #IIS 安全设置 #服务器运维工具 #uniapp #合法域名校验出错 #服务器域名配置不生效 #request域名配置 #已经配置好了但还是报错 #uniapp微信小程序 #框架搭建 #Streamlit #Qwen #AI聊天机器人 #ROS #状态模式 #AI-native # 局域网访问 # 批量处理 #glibc #能源 #汽车 #Llama-Factory # 树莓派 # ARM架构 #Socket #套接字 #I/O多路复用 #字节序 #uni-app #H5 #跨域 #发布上线后跨域报错 #请求接口跨域问题解决 #跨域请求代理配置 #request浏览器跨域 #weston #x11 #x11显示服务器 #研发管理 #禅道 #禅道云端部署 #计算几何 #斜率 #方向归一化 #叉积 #samba #npu #RSO #机器人操作系统 #大剑师 #nodejs面试题 #游戏机 #银河麒麟操作系统 #openssh #华为交换机 #信创终端 #winscp #UDP的API使用 #后端框架 #ESP32 # OTA升级 # 黄山派 #内网 # WebUI # 网络延迟 #zabbix #深度优先 #DFS #集成学习 #远程软件 #STUN # TURN # NAT穿透 #MCP服务器注解 #异步支持 #方法筛选 #声明式编程 #自动筛选机制 #teamviewer #前端框架 #代理服务器 #.net #rsync # 数据同步 #JNI #pxe #bash #blender #设计师 #图像处理 #游戏美术 #技术美术 # 数字人系统 # 远程部署 # Connection refused #claudeCode #content7 #跳槽 #工作 #sql注入 #odoo #rustdesk #p2p #chat #媒体 #Miniconda #Docker #Apple AI #Apple 人工智能 #FoundationModel #Summarize #SwiftUI #大语言模型 #多线程 #free #vmstat #sar #Discord机器人 #云部署 #程序那些事 #r语言 #appche #Ubuntu #muduo #TcpServer #accept #高并发服务器 #spine #TRO #TRO侵权 #TRO和解 #运维工具 #远程开发 #网络攻击模型 #YOLO识别 #YOLO环境搭建Windows #YOLO环境搭建Ubuntu #领域驱动 #LangFlow # 轻量化镜像 # 边缘计算 #OpenHarmony #移动端h5网页 #调用浏览器摄像头并拍照 #开启摄像头权限 #拍照后查看与上传服务器端 #摄像头黑屏打不开问题 #版本控制 #Git入门 #开发工具 #代码托管 #openEuler #服务器IO模型 #非阻塞轮询模型 #多任务并发模型 #异步信号模型 #多路复用模型 #系统安全 #ipmitool #BMC # 黑屏模式 # TTS服务器 #ftp #sftp #入侵 #日志排查 #kmeans #聚类 #远程连接 #jupyter #文件IO #输入输出流 #cpu #串口服务器 #工业级串口服务器 #串口转以太网 #串口设备联网通讯模块 #串口服务器选型 #embedding #WinSCP 下载安装教程 #SFTP #FTP工具 #服务器文件传输 #IndexTTS2 # 阿里云安骑士 # 木马查杀 #Ansible # CosyVoice3 # 批量部署 #AI写作 #AI部署 # ms-swift #PN 结 #服务器线程 # SSL通信 # 动态结构体 #RWK35xx #语音流 #实时传输 #人大金仓 #Kingbase #node #超算中心 #PBS #lsf #excel #报表制作 #职场 #用数据讲故事 #代理模式 #Spring AOP #手机h5网页浏览器 #安卓app #苹果ios APP #手机电脑开启摄像头并排查 #语音生成 #程序人生 #AutoDL #GPU #租显卡 #训练推理 #多进程 #python技巧 #蓝桥杯 #企业级存储 #网络设备 #iot #软件工程 #生信 #pdf #Smokeping #lvs #策略模式 #KMS #slmgr #java大文件上传 #java大文件秒传 #java大文件上传下载 #java文件传输解决方案 #宝塔面板部署RustDesk #RustDesk远程控制手机 #手机远程控制 #铁路桥梁 #DIC技术 #箱梁试验 #裂纹监测 #四点弯曲 #bigtop #hdp #hue #kerberos #可再生能源 #绿色算力 #风电 #pencil #pencil.dev #设计 #zotero #WebDAV #同步失败 #麦克风权限 #访问麦克风并录制音频 #麦克风录制音频后在线播放 #用户拒绝访问麦克风权限怎么办 #uniapp 安卓 苹果ios #将音频保存本地或上传服务器 #轻量化 #低配服务器 #Anything-LLM #IDC服务器 #私有化部署 #express #cherry studio #Node.js # child_process #大模型应用 #API调用 #PyInstaller打包运行 #服务端部署 #raid #raid阵列 #Langchain-Chatchat # 国产化服务器 # 信创 #AI应用编程 # 自动化运维 #PyCharm # 远程调试 # YOLOFuse #欧拉 #若依 #journalctl #GLM-4.6V-Flash-WEB # AI视觉 # 本地部署 #openresty #lua #前端开发 #EN4FE #自由表达演说平台 #演说 #程序员创富 #麒麟 #Syslog #系统日志 #日志分析 #日志监控 #生产服务器问题查询 #日志过滤 #Autodl私有云 #深度服务器配置 # 水冷服务器 # 风冷服务器 #3d #VoxCPM-1.5-TTS # 云端GPU # PyCharm宕机 #儿童AI #图像生成 #pjsip #everything #范式 #AI生成 # outputs目录 # 自动化 #Karalon #AI Test #stl #漏洞修复 #IIS Crypto #YOLOv8 # Docker镜像 #流程图 #论文阅读 #论文笔记 #图论 #国产开源制品管理工具 #Hadess #一文上手 #SSH保活 #jetty #okhttp #健康医疗 #elk #rabbitmq #esp32 arduino #决策树 #HistoryServer #Spark #YARN #jobhistory #ZooKeeper #ZooKeeper面试题 #面试宝典 #深入解析 #ComfyUI # 推理服务器 #SA-PEKS # 关键词猜测攻击 # 盲签名 # 限速机制 #n8n解惑 #小艺 #鸿蒙 #搜索 #编程助手 #内存接口 # 澜起科技 # 服务器主板 #工程实践 # GLM-4.6V-Flash-WEB # 显卡驱动备份 #时序数据库 #模拟退火算法 #计算机毕业设计 #程序定制 #毕设代做 #课设 #源码 #VMware #AI应用 #Hadoop #图像识别 #高考 #uvicorn #uvloop #asgi #event # 服务器迁移 # 回滚方案 #大模型入门 #homelab #Lattepanda #Jellyfin #Plex #Kodi #gpt #API #yolov12 #研究生life #taro #开关电源 #热敏电阻 #PTC热敏电阻 #wps #文件传输 #电脑文件传输 #电脑传输文件 #电脑怎么传输文件到另一台电脑 #电脑传输文件到另一台电脑 #Linux多线程 #eureka #mongodb #Beidou #北斗 #SSR #广播 #组播 #并发服务器 #nacos #银河麒麟aarch64 #国产操作系统 #V11 #kylinos #TensorRT # 推理优化 #simulink #matlab #aiohttp #asyncio #异步 #信息安全 #信息收集 #企业存储 #RustFS #对象存储 #高可用 #软件 #本地生活 #电商系统 #商城 #notepad++ #es安装 #高级IO #poll #gpu #nvcc #cuda #nvidia #Playbook #AI服务器 #neo4j #NoSQL #SQL #LoRA # lora-scripts # 模型微调 #Coturn #TURN #智能体来了 #传统行业 #AI赋能 #log4j #Jetty # 嵌入式服务器 #模块 #RXT4090显卡 #RTX4090 #深度学习服务器 #硬件选型 #.netcore #群晖 #音乐 #IntelliJ IDEA #Spring Boot # AI部署 #SMARC #ARM #材料工程 #数码相机 #智能电视 #VMware创建虚拟机 #远程更新 #缓存更新 #多指令适配 #物料关联计划 # 代理转发 # 跳板机 #挖漏洞 #攻击溯源 #编程 #echarts #warp # 服务器IP # 端口7860 #建筑缺陷 #红外 #数据集 #junit #web服务器 #net core #kestrel #web-server #asp.net-core # 公钥认证 #m3u8 #HLS #移动端H5网页 #APP安卓苹果ios #监控画面 直播视频流 #Reactor #Prometheus #Zabbix #语音合成 # 智能运维 # 性能瓶颈分析 #二值化 #Canny边缘检测 #轮廓检测 #透视变换 #空间计算 #原型模式 #DooTask # 云服务器 #Clawdbot #防毒面罩 #防尘面罩 #postman #I/O模型 #并发 #水平触发、边缘触发 #多路复用 #clickhouse #代理 #数据访问 #MC #MC群组服务器 #磁盘配额 #存储管理 #形考作业 #国家开放大学 #系统运维 #自动化运维 #DHCP #C++ UA Server #SDK #Windows #跨平台开发 #agent #ai大模型 #flutter #select #eclipse #servlet #身体实验室 #健康认知重构 #系统思维 #微行动 #NEAT效应 #亚健康自救 #ICT人 #arm64 #云服务器 #个人电脑 #KMS 激活 #SSH复用 # 远程开发 #wpf #Modbus #MOXA #GATT服务器 #蓝牙低功耗 #SSH别名 #lucene #CS2 #debian13 #BoringSSL #散列表 #远程控制 #云计算运维 #机器视觉 #6D位姿 #UOS #海光K100 #统信 #asp.net大文件上传 #asp.net大文件上传下载 #asp.net大文件上传源码 #ASP.NET断点续传 #asp.net上传文件夹 #asp.net上传大文件 #mssql #PTP_1588 #gPTP #漏洞挖掘 # 鲲鹏 #硬件 #http头信息 #Fun-ASR # 语音识别 #ci/cd #k8s #密码 #firefox #safari # RTX 3090 #ICE #信创国产化 #达梦数据库 # ControlMaster #nmodbus4类库使用教程 #docker-compose #目标跟踪 #PowerBI #企业 #TCP服务器 #开发实战 #全文检索 #银河麒麟服务器系统 #远程桌面 #windbg分析蓝屏教程 #鸿蒙PC ##租显卡 #le audio #低功耗音频 #通信 #连接 #树莓派 #温湿度监控 #WhatsApp通知 #IoT #MySQL #新人首发 #IFix #c++20 # 远程连接 #可撤销IBE #服务器辅助 #私钥更新 #安全性证明 #双线性Diffie-Hellman #Kylin-Server #服务器安装 #Android16 #音频性能实战 #音频进阶 #短剧 #短剧小程序 #短剧系统 #微剧 #Buck #NVIDIA #算力 #交错并联 #DGX #hibernate #nosql #内存治理 #matplotlib #安全架构 #CTF #VMWare Tool #gerrit #opc ua #opc # 环境迁移 #飞牛nas #fnos #tdengine #涛思数据 #服务器解析漏洞 #算力建设 #Proxmox VE #虚拟化 #改行学it #网路编程 #百万并发 #smtp #smtp服务器 #PHP #声源定位 #MUSIC # 远程访问 #tensorflow #mtgsig #美团医药 #美团医药mtgsig #美团医药mtgsig1.2 #ServBay #memcache #ansys #ansys问题解决办法 #ranger #MySQL8.0 #智能体对传统行业冲击 #行业转型 #分布式数据库 #集中式数据库 #业务需求 #选型误 #Socket网络编程 #HarmonyOS #MinIO #雨云服务器 #Minecraft服务器 #教程 #MCSM面板 #sentinel # 服务器配置 # GPU # 串口服务器 # NPort5630 #Python办公自动化 #Python办公 #硬盘克隆 #DiskGenius # 键鼠锁定 #opc模拟服务器 #工程设计 #预混 #扩散 #燃烧知识 #层流 #湍流 #量子计算 #copilot #反向代理 #政务 #adobe #数据迁移 #powerbi #个人助理 #数字员工 #参数估计 #矩估计 #概率论 #Exchange #系统安装 #gmssh #宝塔 #1panel #IPv6 #POC #问答 #交付 #scikit-learn #随机森林 #闲置物品交易系统 #静脉曲张 #腿部健康 #运动 #docker安装seata #AI Agent #开发者工具 # IndexTTS 2.0 #全链路优化 #实战教程 #database #Minecraft #PaperMC #我的世界服务器 #计算机外设 #边缘AI # Kontron # SMARC-sAMX8 #kong #Kong Audio #Kong Audio3 #KongAudio3 #空音3 #空音 #中国民乐 #scanf #printf #getchar #putchar #cin #cout #ET模式 #非阻塞 #sglang #凤希AI伴侣 #remote-ssh #产品经理 #就业 #CMake #Make #C/C++ #OpenAI #故障 #优化 #SSH Agent Forwarding # 容器化 #多模态 #微调 #超参 #LLamafactory #性能 #RAM #vps #AI论文写作工具 #学术写作辅助 #论文创作效率提升 #AI写论文实测 #数字化转型 #实体经济 #商业模式 #软件开发 #数智红包 #商业变革 #创业干货 #AB包 #Go并发 #高并发架构 #Goroutine #系统设计 #Tracker 服务器 #响应最快 #torrent 下载 #2026年 #Aria2 可用 #迅雷可用 #BT工具通用 #FASTMCP #UEFI #BIOS #Legacy BIOS #gateway #Comate #产品运营 #联机教程 #局域网联机 #局域网联机教程 #局域网游戏 #MinIO服务器启动与配置详解 #交换机 #三层交换机 #高斯溅射 #云开发 #Harbor #AI智能棋盘 #Rock Pi S #边缘计算 #c++高并发 #FTP服务器 #uip #b树 # 权限修复 #进程等待 #wait #waitpid #memory mcp #Cursor # HiChatBox # 离线AI #SMTP # 内容安全 # Qwen3Guard #X11转发 #H5网页 #网页白屏 #H5页面空白 #资源加载问题 #打包部署后网页打不开 #HBuilderX #平板 #零售 #智能硬件 #vncdotool #链接VNC服务器 #如何隐藏光标