2026-06-24 f4bd1f3c89d906131495a0aca5aaf82966378510
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.manager;
 
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetSocket;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * IoT 网关 TCP 连接管理器
 * <p>
 * 统一管理 TCP 连接的认证状态、设备会话和消息发送功能:
 * 1. 管理 TCP 连接的认证状态
 * 2. 管理设备会话和在线状态
 * 3. 管理消息发送到设备
 *
 * @author 芋道源码
 */
@Slf4j
public class IotTcpConnectionManager {
 
    /**
     * 最大连接数
     */
    private final int maxConnections;
 
    /**
     * 连接信息映射:NetSocket -> 连接信息
     */
    private final Map<NetSocket, ConnectionInfo> connectionMap = new ConcurrentHashMap<>();
 
    /**
     * 设备 ID -> NetSocket 的映射
     */
    private final Map<Long, NetSocket> deviceSocketMap = new ConcurrentHashMap<>();
 
    public IotTcpConnectionManager(int maxConnections) {
        this.maxConnections = maxConnections;
    }
 
    /**
     * 注册设备连接(包含认证信息)
     *
     * @param socket         TCP 连接
     * @param deviceId       设备 ID
     * @param connectionInfo 连接信息
     */
    public synchronized void registerConnection(NetSocket socket, Long deviceId, ConnectionInfo connectionInfo) {
        // 检查连接数是否已达上限(同步方法确保检查和注册的原子性)
        if (connectionMap.size() >= maxConnections) {
            throw new IllegalStateException("连接数已达上限: " + maxConnections);
        }
        // 如果设备已有其他连接,先清理旧连接
        NetSocket oldSocket = deviceSocketMap.get(deviceId);
        if (oldSocket != null && oldSocket != socket) {
            log.info("[registerConnection][设备已有其他连接,断开旧连接,设备 ID: {},旧连接: {}]",
                    deviceId, oldSocket.remoteAddress());
            // 先清理映射,再关闭连接
            connectionMap.remove(oldSocket);
            oldSocket.close();
        }
 
        // 注册新连接
        connectionMap.put(socket, connectionInfo);
        deviceSocketMap.put(deviceId, socket);
        log.info("[registerConnection][注册设备连接,设备 ID: {},连接: {},product key: {},device name: {}]",
                deviceId, socket.remoteAddress(), connectionInfo.getProductKey(), connectionInfo.getDeviceName());
    }
 
    /**
     * 注销设备连接
     *
     * @param socket TCP 连接
     */
    public void unregisterConnection(NetSocket socket) {
        ConnectionInfo connectionInfo = connectionMap.remove(socket);
        if (connectionInfo == null) {
            return;
        }
        Long deviceId = connectionInfo.getDeviceId();
        // 仅当 deviceSocketMap 中的 socket 是当前 socket 时才移除,避免误删新连接
        deviceSocketMap.remove(deviceId, socket);
        log.info("[unregisterConnection][注销设备连接,设备 ID: {},连接: {}]", deviceId, socket.remoteAddress());
    }
 
    /**
     * 获取连接信息
     */
    public ConnectionInfo getConnectionInfo(NetSocket socket) {
        return connectionMap.get(socket);
    }
 
    /**
     * 根据设备 ID 获取连接信息
     */
    public ConnectionInfo getConnectionInfoByDeviceId(Long deviceId) {
        NetSocket socket = deviceSocketMap.get(deviceId);
        return socket != null ? connectionMap.get(socket) : null;
    }
 
    /**
     * 发送消息到设备
     */
    public boolean sendToDevice(Long deviceId, byte[] data) {
        NetSocket socket = deviceSocketMap.get(deviceId);
        if (socket == null) {
            log.warn("[sendToDevice][设备未连接,设备 ID: {}]", deviceId);
            return false;
        }
 
        try {
            socket.write(Buffer.buffer(data));
            log.debug("[sendToDevice][发送消息成功,设备 ID: {},数据长度: {} 字节]", deviceId, data.length);
            return true;
        } catch (Exception e) {
            log.error("[sendToDevice][发送消息失败,设备 ID: {}]", deviceId, e);
            // 发送失败时清理连接
            unregisterConnection(socket);
            return false;
        }
    }
 
    /**
     * 关闭所有连接
     */
    public void closeAll() {
        // 1. 先复制再清空,避免 closeHandler 回调时并发修改
        List<NetSocket> sockets = new ArrayList<>(connectionMap.keySet());
        connectionMap.clear();
        deviceSocketMap.clear();
        // 2. 关闭所有连接(closeHandler 中 unregisterConnection 发现 map 为空会安全跳过)
        for (NetSocket socket : sockets) {
            try {
                socket.close();
            } catch (Exception ignored) {
                // 连接可能已关闭,忽略异常
            }
        }
    }
 
    /**
     * 连接信息(包含认证信息)
     */
    @Data
    public static class ConnectionInfo {
 
        /**
         * 设备 ID
         */
        private Long deviceId;
        /**
         * 产品 Key
         */
        private String productKey;
        /**
         * 设备名称
         */
        private String deviceName;
 
    }
 
}