package cn.iocoder.yudao.module.iot.gateway.protocol.tcp; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.core.enums.IotProtocolTypeEnum; import cn.iocoder.yudao.module.iot.core.enums.IotSerializeTypeEnum; import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties; import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties.ProtocolProperties; import cn.iocoder.yudao.module.iot.gateway.protocol.IotProtocol; import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.codec.IotTcpFrameCodec; import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.codec.IotTcpFrameCodecFactory; import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.handler.downstream.IotTcpDownstreamHandler; import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.handler.downstream.IotTcpDownstreamSubscriber; import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.handler.upstream.IotTcpUpstreamHandler; import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.manager.IotTcpConnectionManager; import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializer; import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializerManager; import io.vertx.core.Vertx; import io.vertx.core.net.NetServer; import io.vertx.core.net.NetServerOptions; import io.vertx.core.net.PemKeyCertOptions; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import cn.hutool.core.lang.Assert; /** * IoT TCP 协议实现 *
* 基于 Vert.x 实现 TCP 服务器,接收设备上行消息 * * @author 芋道源码 */ @Slf4j public class IotTcpProtocol implements IotProtocol { /** * 协议配置 */ private final ProtocolProperties properties; /** * 服务器 ID(用于消息追踪,全局唯一) */ @Getter private final String serverId; /** * 运行状态 */ @Getter private volatile boolean running = false; /** * Vert.x 实例 */ private Vertx vertx; /** * TCP 服务器 */ private NetServer tcpServer; /** * TCP 连接管理器 */ private final IotTcpConnectionManager connectionManager; /** * 下行消息订阅者 */ private IotTcpDownstreamSubscriber downstreamSubscriber; /** * 消息序列化器 */ private final IotMessageSerializer serializer; /** * TCP 帧编解码器 */ private final IotTcpFrameCodec frameCodec; public IotTcpProtocol(ProtocolProperties properties) { IotTcpConfig tcpConfig = properties.getTcp(); Assert.notNull(tcpConfig, "TCP 协议配置(tcp)不能为空"); Assert.notNull(tcpConfig.getCodec(), "TCP 拆包配置(tcp.codec)不能为空"); this.properties = properties; this.serverId = IotDeviceMessageUtils.generateServerId(properties.getPort()); // 初始化序列化器 IotSerializeTypeEnum serializeType = IotSerializeTypeEnum.of(properties.getSerialize()); Assert.notNull(serializeType, "不支持的序列化类型:" + properties.getSerialize()); IotMessageSerializerManager serializerManager = SpringUtil.getBean(IotMessageSerializerManager.class); this.serializer = serializerManager.get(serializeType); // 初始化帧编解码器 this.frameCodec = IotTcpFrameCodecFactory.create(tcpConfig.getCodec()); // 初始化连接管理器 this.connectionManager = new IotTcpConnectionManager(tcpConfig.getMaxConnections()); } @Override public String getId() { return properties.getId(); } @Override public IotProtocolTypeEnum getType() { return IotProtocolTypeEnum.TCP; } @Override public void start() { if (running) { log.warn("[start][IoT TCP 协议 {} 已经在运行中]", getId()); return; } // 1.1 创建 Vertx 实例 this.vertx = Vertx.vertx(); // 1.2 创建服务器选项 IotTcpConfig tcpConfig = properties.getTcp(); NetServerOptions options = new NetServerOptions() .setPort(properties.getPort()) .setTcpKeepAlive(true) .setTcpNoDelay(true) .setReuseAddress(true) .setIdleTimeout((int) (tcpConfig.getKeepAliveTimeoutMs() / 1000)); // 设置空闲超时 IotGatewayProperties.SslConfig sslConfig = properties.getSsl(); if (sslConfig != null && Boolean.TRUE.equals(sslConfig.getSsl())) { PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions() .setKeyPath(sslConfig.getSslKeyPath()) .setCertPath(sslConfig.getSslCertPath()); options.setSsl(true).setKeyCertOptions(pemKeyCertOptions); } // 1.3 创建服务器并设置连接处理器 tcpServer = vertx.createNetServer(options); tcpServer.connectHandler(socket -> { IotTcpUpstreamHandler handler = new IotTcpUpstreamHandler(serverId, frameCodec, serializer, connectionManager); handler.handle(socket); }); // 1.4 启动 TCP 服务器 try { tcpServer.listen().result(); running = true; log.info("[start][IoT TCP 协议 {} 启动成功,端口:{},serverId:{}]", getId(), properties.getPort(), serverId); // 2. 启动下行消息订阅者 IotTcpDownstreamHandler downstreamHandler = new IotTcpDownstreamHandler(connectionManager, frameCodec, serializer); IotMessageBus messageBus = SpringUtil.getBean(IotMessageBus.class); this.downstreamSubscriber = new IotTcpDownstreamSubscriber(this, downstreamHandler, messageBus); this.downstreamSubscriber.start(); } catch (Exception e) { log.error("[start][IoT TCP 协议 {} 启动失败]", getId(), e); stop0(); throw e; } } @Override public void stop() { if (!running) { return; } stop0(); } private void stop0() { // 1. 停止下行消息订阅者 if (downstreamSubscriber != null) { try { downstreamSubscriber.stop(); log.info("[stop][IoT TCP 协议 {} 下行消息订阅者已停止]", getId()); } catch (Exception e) { log.error("[stop][IoT TCP 协议 {} 下行消息订阅者停止失败]", getId(), e); } downstreamSubscriber = null; } // 2.1 关闭所有连接 connectionManager.closeAll(); // 2.2 关闭 TCP 服务器 if (tcpServer != null) { try { tcpServer.close().result(); log.info("[stop][IoT TCP 协议 {} 服务器已停止]", getId()); } catch (Exception e) { log.error("[stop][IoT TCP 协议 {} 服务器停止失败]", getId(), e); } tcpServer = null; } // 2.3 关闭 Vertx 实例 if (vertx != null) { try { vertx.close().result(); log.info("[stop][IoT TCP 协议 {} Vertx 已关闭]", getId()); } catch (Exception e) { log.error("[stop][IoT TCP 协议 {} Vertx 关闭失败]", getId(), e); } vertx = null; } running = false; log.info("[stop][IoT TCP 协议 {} 已停止]", getId()); } }