YunaiV/ruoyi-vue-pro · warning · IllegalStateException

连接数已达上限: {}

Error message

连接数已达上限: {}

What it means

registerConnection() throws IllegalStateException when the number of registered TCP connections has reached maxConnections. The check (connectionMap.size() >= maxConnections) and the subsequent put run atomically because the whole method is synchronized, so the cap is enforced correctly. The exception propagates to the auth handler, typically rejecting the new device connection.

Source

Thrown at yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/manager/IotTcpConnectionManager.java:55

     * 设备 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());
    }

View on GitHub (pinned to 0418084e22)

Solutions

  1. Raise maxConnections to the expected concurrent device count (plus headroom) in the connection manager config.
  2. Verify every socket close path calls unregisterConnection/removeConnection so slots are freed — check closeHandler wiring in the protocol handler (e.g. IotTcpProtocol / Modbus TCP Server handleConnection).
  3. Catch the IllegalStateException in the auth/register path and respond to the device with a 'server busy' / retry-later instead of propagating.
  4. Monitor connectionMap.size() vs maxConnections and alert before saturation.

Example fix

// before: register throws, killing the auth flow
connectionManager.registerConnection(socket, deviceId, info);

// after: guard and reject gracefully
if (connectionManager.size() >= maxConnections) {
    log.warn("[auth][连接数已达上限, 拒绝新连接 deviceId={} ]", deviceId);
    socket.close();
    return;
}
connectionManager.registerConnection(socket, deviceId, info);
Defensive patterns

Strategy: validation

Validate before calling

// before registering, check the cap and reject gracefully instead of throwing
public boolean canRegister() {
    synchronized (this) {
        return connectionMap.size() < maxConnections;
    }
}
// caller:
if (!connectionManager.canRegister()) {
    log.warn("[auth][连接数已达上限 {},拒绝新连接]", maxConnections);
    socket.close();
    return;
}

Try / catch

// in the auth/register handler, catch the limit error and close the socket cleanly
try {
    connectionManager.registerConnection(socket, deviceId, info);
} catch (IllegalStateException e) {
    log.warn("[register][连接数已达上限,拒绝 deviceId={}]", deviceId);
    socket.close();
}

Prevention

When it happens

Trigger: More than maxConnections devices connect and authenticate concurrently; maxConnections configured too low for the fleet; closed sockets are not unregistered (leak) so the map fills with stale entries; a device reconnect storm exceeds the cap.

Common situations: maxConnections under-provisioned vs deployed device count; a bug where closeHandler/unregisterConnection is missing so closed sockets leak slots; load test exceeding the configured ceiling.

Related errors


AI-assisted analysis of YunaiV/ruoyi-vue-pro@0418084e22 (2026-08-14). Data as JSON: /api/errors/5f2725ae666a9b71. Report an issue: GitHub.