{"record":{"id":"61cad83d60a7fa4e","repo":"YunaiV/ruoyi-vue-pro","slug":"modbus-slaveid-d-identifier-s-functionco","errorCode":null,"errorMessage":"Modbus 读取失败 [slaveId=%d, identifier=%s, functionCode=%d, address=%d, count=%d]","messagePattern":"Modbus 读取失败 \\[slaveId=(.+?), identifier=(.+?), functionCode=(.+?), address=(.+?), count=(.+?)\\]","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java","lineNumber":85,"sourceCode":"                                      Integer registerAddress,\n                                      Integer registerCount,\n                                      String identifier) {\n        return connection.executeBlocking(tcpConnection -> {\n            try {\n                // 1. 创建请求\n                ModbusRequest request = createReadRequest(functionCode, registerAddress, registerCount);\n                request.setUnitID(slaveId);\n\n                // 2. 执行事务（请求）\n                ModbusTCPTransaction transaction = new ModbusTCPTransaction(tcpConnection);\n                transaction.setRequest(request);\n                transaction.execute();\n\n                // 3. 解析响应\n                ModbusResponse response = transaction.getResponse();\n                return extractValues(response, functionCode);\n            } catch (Exception e) {\n                throw new RuntimeException(String.format(\"Modbus 读取失败 [slaveId=%d, identifier=%s, functionCode=%d, address=%d, count=%d]\",\n                        slaveId, identifier, functionCode, registerAddress, registerCount), e);\n            }\n        });\n    }\n\n    /**\n     * 写入 Modbus 数据\n     *\n     * @param connection Modbus 连接\n     * @param slaveId    从站地址\n     * @param point      点位配置\n     * @param values     要写入的值\n     * @return 是否成功\n     */\n    public static Future<Boolean> write(IotModbusTcpClientConnectionManager.ModbusConnection connection,\n                                        Integer slaveId,\n                                        IotModbusPointRespDTO point,\n                                        int[] values) {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/YunaiV/ruoyi-vue-pro/blob/0418084e222612af2fc1141f566af454f9236ab1/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java#L67-L103","documentation":"Wraps ANY exception thrown during a Modbus TCP read transaction inside the connection's executeBlocking block: createReadRequest, transaction.execute(), or extractValues. j2mod's ModbusTCPTransaction throws on TCP connection loss, slave timeout, a Modbus exception response (illegal function/address/data value), or when the response object cannot be cast to the expected response subclass. The wrapping preserves slaveId/identifier/functionCode/address/count for diagnosis.","triggerScenarios":"Slave device offline or TCP connection dropped; wrong slaveId; registerAddress/count out of the device's valid range; function code not implemented by the slave; network interruption mid-transaction; slave returns a Modbus exception code (e.g. 0x83 = illegal function on FC3).","commonSituations":"Device powered off; misconfigured slaveId or register map; flaky serial-to-TCP converter; polling a register the device does not expose; device reboot during poll; j2mod transaction timeout too short for a slow instrument.","solutions":["Inspect the wrapped cause (RuntimeException.getCause()) — a j2mod ExceptionResponse / ModbusException tells whether it is a slave exception (illegal address) vs network (connection reset).","Verify the device is online and the TCP connection is up; ping/Telnet the device.","Confirm slaveId, registerAddress, registerCount and functionCode against the device's register map datasheet.","Reproduce with an independent Modbus tool (e.g. modpoll, QModMaster) reading the same slaveId/address/FC to isolate gateway vs device.","Tune j2mod transaction timeout/retries if the device is slow."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before reading, confirm the connection is alive and the FC/address are valid\nif (!connection.isOpen()) {\n    return Future.failedFuture(new IllegalStateException(\"Modbus 连接未打开\"));\n}\nif (functionCode == null || functionCode < 1 || functionCode > 4) {\n    return Future.failedFuture(new IllegalArgumentException(\"读取功能码非法: \" + functionCode));\n}","typeGuard":"// valid read function codes only\nboolean isValidReadFc(Integer fc) {\n    return fc != null && fc >= 1 && fc <= 4;\n}","tryCatchPattern":"// handle read failure on the returned Future; classify transient vs permanent\nIotModbusTcpClientUtils.read(connection, slaveId, point)\n    .onFailure(e -> {\n        Throwable root = e.getCause() != null ? e.getCause() : e;\n        if (root instanceof java.net.SocketException || root instanceof java.net.SocketTimeoutException) {\n            // transient — schedule a retry after backoff\n        } else {\n            // permanent (illegal address / slave exception) — mark point as error, alert\n        }\n    });","preventionTips":["Validate the device register map (slaveId/address/FC/count) against the datasheet before enabling polling.","Set a j2mod transaction timeout appropriate to the slowest device.","Implement retry-with-backoff for transient network drops; cap retries to avoid read storms.","Monitor per-point read failure rates and disable chronic offenders automatically."],"tags":["modbus","iot","network","polling"],"backgroundTag":null,"analyzedSha":"0418084e222612af2fc1141f566af454f9236ab1","analyzedAt":"2026-08-14T00:56:18.412Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}