1. Modbus概述

Modbus是一种工业通信协议,广泛应用于工业自动化领域,支持串行通信和以太网通信。Modbus协议简单、可靠、开放,是工业设备间通信的标准协议。系统具备Modbus RTU、ASCII、TCP通信、数据采集、故障诊断、性能优化、监控告警等功能。本文将详细介绍Modbus协议的原理、实现方法、性能优化技巧以及在运维实战中的应用。

1.1 Modbus核心价值

  1. 标准化通信: 工业设备间标准化通信协议
  2. 简单可靠: 协议简单,通信可靠
  3. 开放标准: 开放标准,易于实现
  4. 广泛支持: 广泛支持各种工业设备
  5. 实时性: 支持实时数据通信

1.2 Modbus应用场景

  • 工业自动化: 工业自动化控制系统
  • 数据采集: 工业设备数据采集
  • 设备监控: 工业设备状态监控
  • 远程控制: 远程设备控制
  • 系统集成: 工业系统集成

1.3 Modbus协议特性

  • RTU模式: 二进制数据传输
  • ASCII模式: 文本数据传输
  • TCP模式: 以太网TCP/IP通信
  • 主从模式: 主站-从站通信模式
  • 功能码: 支持多种功能码

2. Modbus基础实现

2.1 Modbus配置类

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
/**
* Modbus配置类
* @author 运维实战
*/
@Configuration
@EnableConfigurationProperties(ModbusProperties.class)
public class ModbusConfig {

@Autowired
private ModbusProperties properties;

/**
* Modbus通信服务
* @return Modbus通信服务
*/
@Bean
public ModbusService modbusService() {
return new ModbusService();
}

/**
* Modbus RTU服务
* @return Modbus RTU服务
*/
@Bean
public ModbusRtuService modbusRtuService() {
return new ModbusRtuService();
}

/**
* Modbus ASCII服务
* @return Modbus ASCII服务
*/
@Bean
public ModbusAsciiService modbusAsciiService() {
return new ModbusAsciiService();
}

/**
* Modbus TCP服务
* @return Modbus TCP服务
*/
@Bean
public ModbusTcpService modbusTcpService() {
return new ModbusTcpService();
}

/**
* Modbus设备管理服务
* @return Modbus设备管理服务
*/
@Bean
public ModbusDeviceService modbusDeviceService() {
return new ModbusDeviceService();
}

/**
* Modbus监控服务
* @return Modbus监控服务
*/
@Bean
public ModbusMonitorService modbusMonitorService() {
return new ModbusMonitorService();
}

private static final Logger logger = LoggerFactory.getLogger(ModbusConfig.class);
}

2.2 Modbus属性配置

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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/**
* Modbus属性配置
* @author 运维实战
*/
@Data
@ConfigurationProperties(prefix = "modbus")
public class ModbusProperties {

/**
* 是否启用Modbus
*/
private boolean enableModbus = true;

/**
* Modbus通信模式
*/
private String communicationMode = "RTU"; // RTU, ASCII, TCP

/**
* 串口配置
*/
private SerialPortConfig serialPort = new SerialPortConfig();

/**
* TCP配置
*/
private TcpConfig tcp = new TcpConfig();

/**
* 通信超时时间(毫秒)
*/
private long communicationTimeout = 3000;

/**
* 重试次数
*/
private int retryCount = 3;

/**
* 重试间隔(毫秒)
*/
private long retryInterval = 1000;

/**
* 是否启用CRC校验
*/
private boolean enableCrcCheck = true;

/**
* 是否启用LRC校验
*/
private boolean enableLrcCheck = true;

/**
* 是否启用数据缓存
*/
private boolean enableDataCache = true;

/**
* 数据缓存大小
*/
private int dataCacheSize = 1000;

/**
* 数据缓存过期时间(毫秒)
*/
private long dataCacheExpireTime = 300000;

/**
* 是否启用设备管理
*/
private boolean enableDeviceManagement = true;

/**
* 设备扫描间隔(毫秒)
*/
private long deviceScanInterval = 30000;

/**
* 是否启用故障诊断
*/
private boolean enableFaultDiagnosis = true;

/**
* 故障诊断阈值
*/
private int faultDiagnosisThreshold = 3;

/**
* 是否启用性能监控
*/
private boolean enablePerformanceMonitoring = true;

/**
* 性能监控间隔(毫秒)
*/
private long performanceMonitoringInterval = 30000;

/**
* 是否启用监控
*/
private boolean enableMonitoring = true;

/**
* 监控间隔(毫秒)
*/
private long monitorInterval = 30000;

/**
* 是否启用告警
*/
private boolean enableAlert = true;

/**
* 通信超时告警阈值(毫秒)
*/
private long communicationTimeoutAlertThreshold = 5000;

/**
* 通信失败告警阈值
*/
private int communicationFailureAlertThreshold = 5;

/**
* 设备离线告警阈值(毫秒)
*/
private long deviceOfflineAlertThreshold = 60000;

/**
* 串口配置类
*/
@Data
public static class SerialPortConfig {
/**
* 串口名称
*/
private String portName = "COM1";

/**
* 波特率
*/
private int baudRate = 9600;

/**
* 数据位
*/
private int dataBits = 8;

/**
* 停止位
*/
private int stopBits = 1;

/**
* 校验位
*/
private String parity = "NONE"; // NONE, ODD, EVEN

/**
* 流控制
*/
private String flowControl = "NONE"; // NONE, RTS_CTS, XON_XOFF
}

/**
* TCP配置类
*/
@Data
public static class TcpConfig {
/**
* 服务器地址
*/
private String host = "localhost";

/**
* 服务器端口
*/
private int port = 502;

/**
* 连接超时时间(毫秒)
*/
private long connectionTimeout = 5000;

/**
* 读取超时时间(毫秒)
*/
private long readTimeout = 3000;

/**
* 写入超时时间(毫秒)
*/
private long writeTimeout = 3000;

/**
* 是否启用Keep-Alive
*/
private boolean enableKeepAlive = true;

/**
* Keep-Alive间隔(毫秒)
*/
private long keepAliveInterval = 30000;
}
}

2.3 Modbus数据模型类

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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/**
* Modbus数据模型类
* @author 运维实战
*/
@Data
public class ModbusData {

/**
* 设备地址
*/
private int deviceAddress;

/**
* 功能码
*/
private int functionCode;

/**
* 起始地址
*/
private int startAddress;

/**
* 数据长度
*/
private int dataLength;

/**
* 数据值
*/
private Object dataValue;

/**
* 原始数据
*/
private byte[] rawData;

/**
* 时间戳
*/
private Long timestamp;

/**
* 数据质量
*/
private Integer dataQuality;

/**
* 是否有效
*/
private Boolean isValid;

/**
* 扩展属性
*/
private Map<String, Object> extendedProperties;

public ModbusData() {
this.timestamp = System.currentTimeMillis();
this.isValid = true;
this.extendedProperties = new HashMap<>();
}

public ModbusData(int deviceAddress, int functionCode, int startAddress, int dataLength) {
this();
this.deviceAddress = deviceAddress;
this.functionCode = functionCode;
this.startAddress = startAddress;
this.dataLength = dataLength;
}

/**
* 验证Modbus数据
* @return 是否有效
*/
public boolean validate() {
if (deviceAddress < 1 || deviceAddress > 247) {
return false;
}

if (functionCode < 1 || functionCode > 127) {
return false;
}

if (startAddress < 0 || startAddress > 65535) {
return false;
}

if (dataLength < 1 || dataLength > 125) {
return false;
}

if (timestamp == null || timestamp <= 0) {
return false;
}

return true;
}

/**
* 计算数据质量分数
* @return 数据质量分数
*/
public int calculateDataQuality() {
int quality = 100;

// 根据功能码调整质量
if (functionCode >= 1 && functionCode <= 4) {
// 读取功能码
quality -= 0;
} else if (functionCode >= 5 && functionCode <= 6) {
// 写入功能码
quality -= 5;
} else if (functionCode >= 15 && functionCode <= 16) {
// 批量写入功能码
quality -= 10;
} else {
// 其他功能码
quality -= 20;
}

// 根据数据长度调整质量
if (dataLength > 100) {
quality -= 15;
} else if (dataLength > 50) {
quality -= 10;
} else if (dataLength > 20) {
quality -= 5;
}

return Math.max(0, quality);
}

/**
* 添加扩展属性
* @param key 键
* @param value 值
*/
public void addExtendedProperty(String key, Object value) {
if (extendedProperties == null) {
extendedProperties = new HashMap<>();
}
extendedProperties.put(key, value);
}

/**
* 获取扩展属性
* @param key 键
* @return
*/
public Object getExtendedProperty(String key) {
return extendedProperties != null ? extendedProperties.get(key) : null;
}
}

/**
* Modbus设备信息类
* @author 运维实战
*/
@Data
public class ModbusDevice {

/**
* 设备ID
*/
private String deviceId;

/**
* 设备名称
*/
private String deviceName;

/**
* 设备地址
*/
private int deviceAddress;

/**
* 设备类型
*/
private String deviceType;

/**
* 设备状态
*/
private String deviceStatus;

/**
* 连接状态
*/
private String connectionStatus;

/**
* 最后通信时间
*/
private Long lastCommunicationTime;

/**
* 通信次数
*/
private Long communicationCount;

/**
* 通信成功率
*/
private Double communicationSuccessRate;

/**
* 设备配置
*/
private Map<String, Object> deviceConfig;

/**
* 设备属性
*/
private Map<String, Object> deviceProperties;

public ModbusDevice() {
this.deviceStatus = "UNKNOWN";
this.connectionStatus = "DISCONNECTED";
this.lastCommunicationTime = 0L;
this.communicationCount = 0L;
this.communicationSuccessRate = 0.0;
this.deviceConfig = new HashMap<>();
this.deviceProperties = new HashMap<>();
}

public ModbusDevice(String deviceId, String deviceName, int deviceAddress) {
this();
this.deviceId = deviceId;
this.deviceName = deviceName;
this.deviceAddress = deviceAddress;
}

/**
* 验证Modbus设备
* @return 是否有效
*/
public boolean validate() {
if (deviceId == null || deviceId.isEmpty()) {
return false;
}

if (deviceName == null || deviceName.isEmpty()) {
return false;
}

if (deviceAddress < 1 || deviceAddress > 247) {
return false;
}

return true;
}

/**
* 更新通信统计
* @param success 是否成功
*/
public void updateCommunicationStats(boolean success) {
this.communicationCount++;
this.lastCommunicationTime = System.currentTimeMillis();

if (success) {
this.communicationSuccessRate = (this.communicationSuccessRate * (this.communicationCount - 1) + 100.0) / this.communicationCount;
} else {
this.communicationSuccessRate = (this.communicationSuccessRate * (this.communicationCount - 1)) / this.communicationCount;
}
}

/**
* 是否在线
* @return 是否在线
*/
public boolean isOnline() {
return "CONNECTED".equals(connectionStatus) &&
(System.currentTimeMillis() - lastCommunicationTime) < 60000; // 1分钟内
}

/**
* 添加设备配置
* @param key 键
* @param value 值
*/
public void addDeviceConfig(String key, Object value) {
if (deviceConfig == null) {
deviceConfig = new HashMap<>();
}
deviceConfig.put(key, value);
}

/**
* 添加设备属性
* @param key 键
* @param value 值
*/
public void addDeviceProperty(String key, Object value) {
if (deviceProperties == null) {
deviceProperties = new HashMap<>();
}
deviceProperties.put(key, value);
}
}

2.4 基础Modbus服务

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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
/**
* 基础Modbus服务
* @author 运维实战
*/
@Service
public class ModbusService {

@Autowired
private ModbusProperties properties;

@Autowired
private ModbusRtuService modbusRtuService;

@Autowired
private ModbusAsciiService modbusAsciiService;

@Autowired
private ModbusTcpService modbusTcpService;

@Autowired
private ModbusDeviceService modbusDeviceService;

@Autowired
private ModbusMonitorService modbusMonitorService;

private static final Logger logger = LoggerFactory.getLogger(ModbusService.class);

/**
* 读取Modbus数据
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataLength 数据长度
* @return 读取结果
*/
public ModbusReadResult readModbusData(int deviceAddress, int functionCode, int startAddress, int dataLength) {
logger.info("读取Modbus数据,设备地址: {}, 功能码: {}, 起始地址: {}, 数据长度: {}",
deviceAddress, functionCode, startAddress, dataLength);

ModbusReadResult result = new ModbusReadResult();
result.setDeviceAddress(deviceAddress);
result.setFunctionCode(functionCode);
result.setStartAddress(startAddress);
result.setDataLength(dataLength);
result.setStartTime(System.currentTimeMillis());

try {
// 验证参数
if (!validateModbusParameters(deviceAddress, functionCode, startAddress, dataLength)) {
result.setSuccess(false);
result.setError("参数验证失败");
result.setEndTime(System.currentTimeMillis());
return result;
}

// 根据通信模式选择服务
ModbusReadResult readResult = null;
switch (properties.getCommunicationMode().toUpperCase()) {
case "RTU":
readResult = modbusRtuService.readData(deviceAddress, functionCode, startAddress, dataLength);
break;
case "ASCII":
readResult = modbusAsciiService.readData(deviceAddress, functionCode, startAddress, dataLength);
break;
case "TCP":
readResult = modbusTcpService.readData(deviceAddress, functionCode, startAddress, dataLength);
break;
default:
result.setSuccess(false);
result.setError("不支持的通信模式: " + properties.getCommunicationMode());
result.setEndTime(System.currentTimeMillis());
return result;
}

if (readResult != null && readResult.isSuccess()) {
result.setSuccess(true);
result.setData(readResult.getData());
result.setRawData(readResult.getRawData());
result.setEndTime(System.currentTimeMillis());

// 更新设备通信统计
modbusDeviceService.updateDeviceCommunicationStats(deviceAddress, true);

// 记录读取成功指标
modbusMonitorService.recordModbusRead(deviceAddress, functionCode, true);

logger.info("Modbus数据读取成功,设备地址: {}, 功能码: {}, 耗时: {}ms",
deviceAddress, functionCode, result.getDuration());
} else {
result.setSuccess(false);
result.setError(readResult != null ? readResult.getError() : "读取失败");
result.setEndTime(System.currentTimeMillis());

// 更新设备通信统计
modbusDeviceService.updateDeviceCommunicationStats(deviceAddress, false);

// 记录读取失败指标
modbusMonitorService.recordModbusRead(deviceAddress, functionCode, false);
}

return result;

} catch (Exception e) {
logger.error("Modbus数据读取异常,设备地址: {}", deviceAddress, e);
result.setSuccess(false);
result.setError("Modbus数据读取异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());

// 更新设备通信统计
modbusDeviceService.updateDeviceCommunicationStats(deviceAddress, false);

// 记录读取异常指标
modbusMonitorService.recordModbusRead(deviceAddress, functionCode, false);

return result;
}
}

/**
* 写入Modbus数据
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataValue 数据值
* @return 写入结果
*/
public ModbusWriteResult writeModbusData(int deviceAddress, int functionCode, int startAddress, Object dataValue) {
logger.info("写入Modbus数据,设备地址: {}, 功能码: {}, 起始地址: {}, 数据值: {}",
deviceAddress, functionCode, startAddress, dataValue);

ModbusWriteResult result = new ModbusWriteResult();
result.setDeviceAddress(deviceAddress);
result.setFunctionCode(functionCode);
result.setStartAddress(startAddress);
result.setDataValue(dataValue);
result.setStartTime(System.currentTimeMillis());

try {
// 验证参数
if (!validateModbusParameters(deviceAddress, functionCode, startAddress, 1)) {
result.setSuccess(false);
result.setError("参数验证失败");
result.setEndTime(System.currentTimeMillis());
return result;
}

// 根据通信模式选择服务
ModbusWriteResult writeResult = null;
switch (properties.getCommunicationMode().toUpperCase()) {
case "RTU":
writeResult = modbusRtuService.writeData(deviceAddress, functionCode, startAddress, dataValue);
break;
case "ASCII":
writeResult = modbusAsciiService.writeData(deviceAddress, functionCode, startAddress, dataValue);
break;
case "TCP":
writeResult = modbusTcpService.writeData(deviceAddress, functionCode, startAddress, dataValue);
break;
default:
result.setSuccess(false);
result.setError("不支持的通信模式: " + properties.getCommunicationMode());
result.setEndTime(System.currentTimeMillis());
return result;
}

if (writeResult != null && writeResult.isSuccess()) {
result.setSuccess(true);
result.setEndTime(System.currentTimeMillis());

// 更新设备通信统计
modbusDeviceService.updateDeviceCommunicationStats(deviceAddress, true);

// 记录写入成功指标
modbusMonitorService.recordModbusWrite(deviceAddress, functionCode, true);

logger.info("Modbus数据写入成功,设备地址: {}, 功能码: {}, 耗时: {}ms",
deviceAddress, functionCode, result.getDuration());
} else {
result.setSuccess(false);
result.setError(writeResult != null ? writeResult.getError() : "写入失败");
result.setEndTime(System.currentTimeMillis());

// 更新设备通信统计
modbusDeviceService.updateDeviceCommunicationStats(deviceAddress, false);

// 记录写入失败指标
modbusMonitorService.recordModbusWrite(deviceAddress, functionCode, false);
}

return result;

} catch (Exception e) {
logger.error("Modbus数据写入异常,设备地址: {}", deviceAddress, e);
result.setSuccess(false);
result.setError("Modbus数据写入异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());

// 更新设备通信统计
modbusDeviceService.updateDeviceCommunicationStats(deviceAddress, false);

// 记录写入异常指标
modbusMonitorService.recordModbusWrite(deviceAddress, functionCode, false);

return result;
}
}

/**
* 批量读取Modbus数据
* @param readRequests 读取请求列表
* @return 批量读取结果
*/
public ModbusBatchReadResult batchReadModbusData(List<ModbusReadRequest> readRequests) {
logger.info("批量读取Modbus数据,请求数量: {}", readRequests.size());

ModbusBatchReadResult result = new ModbusBatchReadResult();
result.setTotalCount(readRequests.size());
result.setStartTime(System.currentTimeMillis());

try {
List<ModbusReadResult> readResults = new ArrayList<>();
int successCount = 0;
int failureCount = 0;

for (ModbusReadRequest request : readRequests) {
try {
ModbusReadResult readResult = readModbusData(
request.getDeviceAddress(),
request.getFunctionCode(),
request.getStartAddress(),
request.getDataLength()
);

readResults.add(readResult);

if (readResult.isSuccess()) {
successCount++;
} else {
failureCount++;
}
} catch (Exception e) {
logger.error("批量读取单条数据异常,设备地址: {}", request.getDeviceAddress(), e);
failureCount++;
}
}

result.setSuccessCount(successCount);
result.setFailureCount(failureCount);
result.setReadResults(readResults);
result.setEndTime(System.currentTimeMillis());

// 记录批量读取指标
modbusMonitorService.recordModbusBatchRead(readRequests.size(), successCount);

logger.info("批量Modbus数据读取完成,总数: {}, 成功: {}, 失败: {}, 耗时: {}ms",
result.getTotalCount(), result.getSuccessCount(), result.getFailureCount(), result.getDuration());

return result;

} catch (Exception e) {
logger.error("批量Modbus数据读取异常", e);
result.setSuccess(false);
result.setError("批量Modbus数据读取异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());
return result;
}
}

/**
* 获取Modbus设备信息
* @param deviceAddress 设备地址
* @return 设备信息
*/
public ModbusDevice getModbusDevice(int deviceAddress) {
logger.info("获取Modbus设备信息,设备地址: {}", deviceAddress);

try {
ModbusDevice device = modbusDeviceService.getDevice(deviceAddress);

if (device != null) {
logger.info("获取Modbus设备信息成功,设备地址: {}, 设备名称: {}",
deviceAddress, device.getDeviceName());
} else {
logger.warn("Modbus设备不存在,设备地址: {}", deviceAddress);
}

return device;

} catch (Exception e) {
logger.error("获取Modbus设备信息异常,设备地址: {}", deviceAddress, e);
return null;
}
}

/**
* 扫描Modbus设备
* @return 扫描结果
*/
public ModbusScanResult scanModbusDevices() {
logger.info("扫描Modbus设备");

ModbusScanResult result = new ModbusScanResult();
result.setStartTime(System.currentTimeMillis());

try {
List<ModbusDevice> devices = modbusDeviceService.scanDevices();

result.setSuccess(true);
result.setDevices(devices);
result.setDeviceCount(devices.size());
result.setEndTime(System.currentTimeMillis());

logger.info("Modbus设备扫描完成,发现设备数量: {}, 耗时: {}ms",
result.getDeviceCount(), result.getDuration());

return result;

} catch (Exception e) {
logger.error("Modbus设备扫描异常", e);
result.setSuccess(false);
result.setError("Modbus设备扫描异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());
return result;
}
}

/**
* 验证Modbus参数
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataLength 数据长度
* @return 是否有效
*/
private boolean validateModbusParameters(int deviceAddress, int functionCode, int startAddress, int dataLength) {
if (deviceAddress < 1 || deviceAddress > 247) {
return false;
}

if (functionCode < 1 || functionCode > 127) {
return false;
}

if (startAddress < 0 || startAddress > 65535) {
return false;
}

if (dataLength < 1 || dataLength > 125) {
return false;
}

return true;
}
}

2.5 Modbus结果类

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
167
168
169
170
171
172
173
174
/**
* Modbus读取结果类
* @author 运维实战
*/
@Data
public class ModbusReadResult {

private boolean success;
private int deviceAddress;
private int functionCode;
private int startAddress;
private int dataLength;
private Object data;
private byte[] rawData;
private String error;
private long startTime;
private long endTime;

public ModbusReadResult() {
this.success = false;
}

/**
* 获取读取耗时
* @return 读取耗时(毫秒)
*/
public long getDuration() {
return endTime - startTime;
}

/**
* 是否成功
* @return 是否成功
*/
public boolean isSuccess() {
return success;
}
}

/**
* Modbus写入结果类
* @author 运维实战
*/
@Data
public class ModbusWriteResult {

private boolean success;
private int deviceAddress;
private int functionCode;
private int startAddress;
private Object dataValue;
private String error;
private long startTime;
private long endTime;

public ModbusWriteResult() {
this.success = false;
}

/**
* 获取写入耗时
* @return 写入耗时(毫秒)
*/
public long getDuration() {
return endTime - startTime;
}

/**
* 是否成功
* @return 是否成功
*/
public boolean isSuccess() {
return success;
}
}

/**
* Modbus批量读取结果类
* @author 运维实战
*/
@Data
public class ModbusBatchReadResult {

private boolean success;
private int totalCount;
private int successCount;
private int failureCount;
private List<ModbusReadResult> readResults;
private String error;
private long startTime;
private long endTime;

public ModbusBatchReadResult() {
this.success = false;
this.successCount = 0;
this.failureCount = 0;
this.readResults = new ArrayList<>();
}

/**
* 获取读取耗时
* @return 读取耗时(毫秒)
*/
public long getDuration() {
return endTime - startTime;
}

/**
* 是否成功
* @return 是否成功
*/
public boolean isSuccess() {
return success;
}
}

/**
* Modbus扫描结果类
* @author 运维实战
*/
@Data
public class ModbusScanResult {

private boolean success;
private List<ModbusDevice> devices;
private int deviceCount;
private String error;
private long startTime;
private long endTime;

public ModbusScanResult() {
this.success = false;
this.devices = new ArrayList<>();
this.deviceCount = 0;
}

/**
* 获取扫描耗时
* @return 扫描耗时(毫秒)
*/
public long getDuration() {
return endTime - startTime;
}

/**
* 是否成功
* @return 是否成功
*/
public boolean isSuccess() {
return success;
}
}

/**
* Modbus读取请求类
* @author 运维实战
*/
@Data
public class ModbusReadRequest {

private int deviceAddress;
private int functionCode;
private int startAddress;
private int dataLength;

public ModbusReadRequest() {}

public ModbusReadRequest(int deviceAddress, int functionCode, int startAddress, int dataLength) {
this.deviceAddress = deviceAddress;
this.functionCode = functionCode;
this.startAddress = startAddress;
this.dataLength = dataLength;
}
}

3. 高级功能实现

3.1 Modbus RTU服务

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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
/**
* Modbus RTU服务
* @author 运维实战
*/
@Service
public class ModbusRtuService {

@Autowired
private ModbusProperties properties;

@Autowired
private ModbusMonitorService modbusMonitorService;

private SerialPort serialPort;
private SerialPortEventListener serialPortEventListener;

private static final Logger logger = LoggerFactory.getLogger(ModbusRtuService.class);

/**
* 初始化串口
*/
@PostConstruct
public void initSerialPort() {
try {
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(properties.getSerialPort().getPortName());
serialPort = (SerialPort) portIdentifier.open("ModbusRTU", 2000);

serialPort.setSerialPortParams(
properties.getSerialPort().getBaudRate(),
properties.getSerialPort().getDataBits(),
properties.getSerialPort().getStopBits(),
getParity(properties.getSerialPort().getParity())
);

serialPort.setFlowControlMode(getFlowControl(properties.getSerialPort().getFlowControl()));

logger.info("Modbus RTU串口初始化成功,端口: {}", properties.getSerialPort().getPortName());

} catch (Exception e) {
logger.error("Modbus RTU串口初始化失败", e);
}
}

/**
* 关闭串口
*/
@PreDestroy
public void closeSerialPort() {
try {
if (serialPort != null) {
serialPort.close();
logger.info("Modbus RTU串口关闭成功");
}
} catch (Exception e) {
logger.error("Modbus RTU串口关闭失败", e);
}
}

/**
* 读取数据
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataLength 数据长度
* @return 读取结果
*/
public ModbusReadResult readData(int deviceAddress, int functionCode, int startAddress, int dataLength) {
logger.info("Modbus RTU读取数据,设备地址: {}, 功能码: {}", deviceAddress, functionCode);

ModbusReadResult result = new ModbusReadResult();
result.setDeviceAddress(deviceAddress);
result.setFunctionCode(functionCode);
result.setStartAddress(startAddress);
result.setDataLength(dataLength);
result.setStartTime(System.currentTimeMillis());

try {
// 构建RTU请求帧
byte[] requestFrame = buildRtuRequestFrame(deviceAddress, functionCode, startAddress, dataLength);

// 发送请求
sendRequest(requestFrame);

// 接收响应
byte[] responseFrame = receiveResponse();

if (responseFrame != null && responseFrame.length > 0) {
// 解析响应
ModbusReadResult parseResult = parseRtuResponse(responseFrame, functionCode);

if (parseResult != null && parseResult.isSuccess()) {
result.setSuccess(true);
result.setData(parseResult.getData());
result.setRawData(responseFrame);
} else {
result.setSuccess(false);
result.setError("响应解析失败");
}
} else {
result.setSuccess(false);
result.setError("接收响应超时");
}

result.setEndTime(System.currentTimeMillis());

logger.info("Modbus RTU读取数据完成,设备地址: {}, 成功: {}, 耗时: {}ms",
deviceAddress, result.isSuccess(), result.getDuration());

return result;

} catch (Exception e) {
logger.error("Modbus RTU读取数据异常,设备地址: {}", deviceAddress, e);
result.setSuccess(false);
result.setError("Modbus RTU读取数据异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());
return result;
}
}

/**
* 写入数据
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataValue 数据值
* @return 写入结果
*/
public ModbusWriteResult writeData(int deviceAddress, int functionCode, int startAddress, Object dataValue) {
logger.info("Modbus RTU写入数据,设备地址: {}, 功能码: {}", deviceAddress, functionCode);

ModbusWriteResult result = new ModbusWriteResult();
result.setDeviceAddress(deviceAddress);
result.setFunctionCode(functionCode);
result.setStartAddress(startAddress);
result.setDataValue(dataValue);
result.setStartTime(System.currentTimeMillis());

try {
// 构建RTU请求帧
byte[] requestFrame = buildRtuWriteRequestFrame(deviceAddress, functionCode, startAddress, dataValue);

// 发送请求
sendRequest(requestFrame);

// 接收响应
byte[] responseFrame = receiveResponse();

if (responseFrame != null && responseFrame.length > 0) {
// 解析响应
ModbusWriteResult parseResult = parseRtuWriteResponse(responseFrame, functionCode);

if (parseResult != null && parseResult.isSuccess()) {
result.setSuccess(true);
} else {
result.setSuccess(false);
result.setError("响应解析失败");
}
} else {
result.setSuccess(false);
result.setError("接收响应超时");
}

result.setEndTime(System.currentTimeMillis());

logger.info("Modbus RTU写入数据完成,设备地址: {}, 成功: {}, 耗时: {}ms",
deviceAddress, result.isSuccess(), result.getDuration());

return result;

} catch (Exception e) {
logger.error("Modbus RTU写入数据异常,设备地址: {}", deviceAddress, e);
result.setSuccess(false);
result.setError("Modbus RTU写入数据异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());
return result;
}
}

/**
* 构建RTU请求帧
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataLength 数据长度
* @return 请求帧
*/
private byte[] buildRtuRequestFrame(int deviceAddress, int functionCode, int startAddress, int dataLength) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();

try {
// 设备地址
baos.write(deviceAddress);

// 功能码
baos.write(functionCode);

// 起始地址(高字节在前)
baos.write((startAddress >> 8) & 0xFF);
baos.write(startAddress & 0xFF);

// 数据长度(高字节在前)
baos.write((dataLength >> 8) & 0xFF);
baos.write(dataLength & 0xFF);

// 计算CRC
byte[] frame = baos.toByteArray();
int crc = calculateCrc(frame);

// 添加CRC(低字节在前)
baos.write(crc & 0xFF);
baos.write((crc >> 8) & 0xFF);

return baos.toByteArray();

} catch (Exception e) {
logger.error("构建RTU请求帧异常", e);
return new byte[0];
}
}

/**
* 构建RTU写入请求帧
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataValue 数据值
* @return 请求帧
*/
private byte[] buildRtuWriteRequestFrame(int deviceAddress, int functionCode, int startAddress, Object dataValue) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();

try {
// 设备地址
baos.write(deviceAddress);

// 功能码
baos.write(functionCode);

// 起始地址(高字节在前)
baos.write((startAddress >> 8) & 0xFF);
baos.write(startAddress & 0xFF);

// 写入数据
if (dataValue instanceof Integer) {
int value = (Integer) dataValue;
baos.write((value >> 8) & 0xFF);
baos.write(value & 0xFF);
} else if (dataValue instanceof Boolean) {
boolean value = (Boolean) dataValue;
baos.write(value ? 0xFF : 0x00);
baos.write(0x00);
}

// 计算CRC
byte[] frame = baos.toByteArray();
int crc = calculateCrc(frame);

// 添加CRC(低字节在前)
baos.write(crc & 0xFF);
baos.write((crc >> 8) & 0xFF);

return baos.toByteArray();

} catch (Exception e) {
logger.error("构建RTU写入请求帧异常", e);
return new byte[0];
}
}

/**
* 发送请求
* @param requestFrame 请求帧
*/
private void sendRequest(byte[] requestFrame) throws Exception {
if (serialPort != null) {
OutputStream outputStream = serialPort.getOutputStream();
outputStream.write(requestFrame);
outputStream.flush();
}
}

/**
* 接收响应
* @return 响应帧
*/
private byte[] receiveResponse() throws Exception {
if (serialPort != null) {
InputStream inputStream = serialPort.getInputStream();

// 等待响应
Thread.sleep(100);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[256];
int bytesRead;

while ((bytesRead = inputStream.read(buffer)) > 0) {
baos.write(buffer, 0, bytesRead);

// 检查是否接收完整
if (baos.size() >= 3) { // 最小响应长度
break;
}
}

return baos.toByteArray();
}

return new byte[0];
}

/**
* 解析RTU响应
* @param responseFrame 响应帧
* @param functionCode 功能码
* @return 解析结果
*/
private ModbusReadResult parseRtuResponse(byte[] responseFrame, int functionCode) {
try {
if (responseFrame.length < 5) {
return null;
}

ModbusReadResult result = new ModbusReadResult();
result.setFunctionCode(functionCode);

// 检查CRC
if (properties.isEnableCrcCheck()) {
byte[] data = new byte[responseFrame.length - 2];
System.arraycopy(responseFrame, 0, data, 0, data.length);
int calculatedCrc = calculateCrc(data);
int receivedCrc = ((responseFrame[responseFrame.length - 1] & 0xFF) << 8) |
(responseFrame[responseFrame.length - 2] & 0xFF);

if (calculatedCrc != receivedCrc) {
result.setSuccess(false);
result.setError("CRC校验失败");
return result;
}
}

// 解析数据
if (functionCode == 0x01 || functionCode == 0x02) {
// 读取线圈状态
int byteCount = responseFrame[2] & 0xFF;
byte[] data = new byte[byteCount];
System.arraycopy(responseFrame, 3, data, 0, byteCount);
result.setData(data);
} else if (functionCode == 0x03 || functionCode == 0x04) {
// 读取保持寄存器
int byteCount = responseFrame[2] & 0xFF;
byte[] data = new byte[byteCount];
System.arraycopy(responseFrame, 3, data, 0, byteCount);
result.setData(data);
}

result.setSuccess(true);
result.setRawData(responseFrame);

return result;

} catch (Exception e) {
logger.error("解析RTU响应异常", e);
return null;
}
}

/**
* 解析RTU写入响应
* @param responseFrame 响应帧
* @param functionCode 功能码
* @return 解析结果
*/
private ModbusWriteResult parseRtuWriteResponse(byte[] responseFrame, int functionCode) {
try {
if (responseFrame.length < 5) {
return null;
}

ModbusWriteResult result = new ModbusWriteResult();
result.setFunctionCode(functionCode);

// 检查CRC
if (properties.isEnableCrcCheck()) {
byte[] data = new byte[responseFrame.length - 2];
System.arraycopy(responseFrame, 0, data, 0, data.length);
int calculatedCrc = calculateCrc(data);
int receivedCrc = ((responseFrame[responseFrame.length - 1] & 0xFF) << 8) |
(responseFrame[responseFrame.length - 2] & 0xFF);

if (calculatedCrc != receivedCrc) {
result.setSuccess(false);
result.setError("CRC校验失败");
return result;
}
}

result.setSuccess(true);

return result;

} catch (Exception e) {
logger.error("解析RTU写入响应异常", e);
return null;
}
}

/**
* 计算CRC
* @param data 数据
* @return CRC值
*/
private int calculateCrc(byte[] data) {
int crc = 0xFFFF;

for (byte b : data) {
crc ^= (b & 0xFF);

for (int i = 0; i < 8; i++) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}

return crc;
}

/**
* 获取校验位
* @param parity 校验位字符串
* @return 校验位值
*/
private int getParity(String parity) {
switch (parity.toUpperCase()) {
case "ODD":
return SerialPort.ODDPARITY;
case "EVEN":
return SerialPort.EVENPARITY;
default:
return SerialPort.NOPARITY;
}
}

/**
* 获取流控制
* @param flowControl 流控制字符串
* @return 流控制值
*/
private int getFlowControl(String flowControl) {
switch (flowControl.toUpperCase()) {
case "RTS_CTS":
return SerialPort.FLOWCONTROL_RTSCTS_IN | SerialPort.FLOWCONTROL_RTSCTS_OUT;
case "XON_XOFF":
return SerialPort.FLOWCONTROL_XONXOFF_IN | SerialPort.FLOWCONTROL_XONXOFF_OUT;
default:
return SerialPort.FLOWCONTROL_NONE;
}
}
}

3.2 Modbus TCP服务

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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
/**
* Modbus TCP服务
* @author 运维实战
*/
@Service
public class ModbusTcpService {

@Autowired
private ModbusProperties properties;

@Autowired
private ModbusMonitorService modbusMonitorService;

private Socket socket;
private DataInputStream inputStream;
private DataOutputStream outputStream;

private static final Logger logger = LoggerFactory.getLogger(ModbusTcpService.class);

/**
* 初始化TCP连接
*/
@PostConstruct
public void initTcpConnection() {
try {
connect();
logger.info("Modbus TCP连接初始化成功,地址: {}:{}",
properties.getTcp().getHost(), properties.getTcp().getPort());
} catch (Exception e) {
logger.error("Modbus TCP连接初始化失败", e);
}
}

/**
* 关闭TCP连接
*/
@PreDestroy
public void closeTcpConnection() {
try {
disconnect();
logger.info("Modbus TCP连接关闭成功");
} catch (Exception e) {
logger.error("Modbus TCP连接关闭失败", e);
}
}

/**
* 连接TCP服务器
*/
private void connect() throws Exception {
socket = new Socket();
socket.connect(new InetSocketAddress(properties.getTcp().getHost(), properties.getTcp().getPort()),
(int) properties.getTcp().getConnectionTimeout());

inputStream = new DataInputStream(socket.getInputStream());
outputStream = new DataOutputStream(socket.getOutputStream());

// 设置Keep-Alive
if (properties.getTcp().isEnableKeepAlive()) {
socket.setKeepAlive(true);
}
}

/**
* 断开TCP连接
*/
private void disconnect() throws Exception {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
if (socket != null) {
socket.close();
}
}

/**
* 读取数据
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataLength 数据长度
* @return 读取结果
*/
public ModbusReadResult readData(int deviceAddress, int functionCode, int startAddress, int dataLength) {
logger.info("Modbus TCP读取数据,设备地址: {}, 功能码: {}", deviceAddress, functionCode);

ModbusReadResult result = new ModbusReadResult();
result.setDeviceAddress(deviceAddress);
result.setFunctionCode(functionCode);
result.setStartAddress(startAddress);
result.setDataLength(dataLength);
result.setStartTime(System.currentTimeMillis());

try {
// 确保连接
if (!isConnected()) {
connect();
}

// 构建TCP请求帧
byte[] requestFrame = buildTcpRequestFrame(deviceAddress, functionCode, startAddress, dataLength);

// 发送请求
sendRequest(requestFrame);

// 接收响应
byte[] responseFrame = receiveResponse();

if (responseFrame != null && responseFrame.length > 0) {
// 解析响应
ModbusReadResult parseResult = parseTcpResponse(responseFrame, functionCode);

if (parseResult != null && parseResult.isSuccess()) {
result.setSuccess(true);
result.setData(parseResult.getData());
result.setRawData(responseFrame);
} else {
result.setSuccess(false);
result.setError("响应解析失败");
}
} else {
result.setSuccess(false);
result.setError("接收响应超时");
}

result.setEndTime(System.currentTimeMillis());

logger.info("Modbus TCP读取数据完成,设备地址: {}, 成功: {}, 耗时: {}ms",
deviceAddress, result.isSuccess(), result.getDuration());

return result;

} catch (Exception e) {
logger.error("Modbus TCP读取数据异常,设备地址: {}", deviceAddress, e);
result.setSuccess(false);
result.setError("Modbus TCP读取数据异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());
return result;
}
}

/**
* 写入数据
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataValue 数据值
* @return 写入结果
*/
public ModbusWriteResult writeData(int deviceAddress, int functionCode, int startAddress, Object dataValue) {
logger.info("Modbus TCP写入数据,设备地址: {}, 功能码: {}", deviceAddress, functionCode);

ModbusWriteResult result = new ModbusWriteResult();
result.setDeviceAddress(deviceAddress);
result.setFunctionCode(functionCode);
result.setStartAddress(startAddress);
result.setDataValue(dataValue);
result.setStartTime(System.currentTimeMillis());

try {
// 确保连接
if (!isConnected()) {
connect();
}

// 构建TCP请求帧
byte[] requestFrame = buildTcpWriteRequestFrame(deviceAddress, functionCode, startAddress, dataValue);

// 发送请求
sendRequest(requestFrame);

// 接收响应
byte[] responseFrame = receiveResponse();

if (responseFrame != null && responseFrame.length > 0) {
// 解析响应
ModbusWriteResult parseResult = parseTcpWriteResponse(responseFrame, functionCode);

if (parseResult != null && parseResult.isSuccess()) {
result.setSuccess(true);
} else {
result.setSuccess(false);
result.setError("响应解析失败");
}
} else {
result.setSuccess(false);
result.setError("接收响应超时");
}

result.setEndTime(System.currentTimeMillis());

logger.info("Modbus TCP写入数据完成,设备地址: {}, 成功: {}, 耗时: {}ms",
deviceAddress, result.isSuccess(), result.getDuration());

return result;

} catch (Exception e) {
logger.error("Modbus TCP写入数据异常,设备地址: {}", deviceAddress, e);
result.setSuccess(false);
result.setError("Modbus TCP写入数据异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());
return result;
}
}

/**
* 构建TCP请求帧
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataLength 数据长度
* @return 请求帧
*/
private byte[] buildTcpRequestFrame(int deviceAddress, int functionCode, int startAddress, int dataLength) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();

try {
// 事务标识符(高字节在前)
int transactionId = (int) (System.currentTimeMillis() & 0xFFFF);
baos.write((transactionId >> 8) & 0xFF);
baos.write(transactionId & 0xFF);

// 协议标识符(0x0000)
baos.write(0x00);
baos.write(0x00);

// 长度(高字节在前)
int length = 6; // 设备地址 + 功能码 + 起始地址 + 数据长度
baos.write((length >> 8) & 0xFF);
baos.write(length & 0xFF);

// 设备地址
baos.write(deviceAddress);

// 功能码
baos.write(functionCode);

// 起始地址(高字节在前)
baos.write((startAddress >> 8) & 0xFF);
baos.write(startAddress & 0xFF);

// 数据长度(高字节在前)
baos.write((dataLength >> 8) & 0xFF);
baos.write(dataLength & 0xFF);

return baos.toByteArray();

} catch (Exception e) {
logger.error("构建TCP请求帧异常", e);
return new byte[0];
}
}

/**
* 构建TCP写入请求帧
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataValue 数据值
* @return 请求帧
*/
private byte[] buildTcpWriteRequestFrame(int deviceAddress, int functionCode, int startAddress, Object dataValue) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();

try {
// 事务标识符(高字节在前)
int transactionId = (int) (System.currentTimeMillis() & 0xFFFF);
baos.write((transactionId >> 8) & 0xFF);
baos.write(transactionId & 0xFF);

// 协议标识符(0x0000)
baos.write(0x00);
baos.write(0x00);

// 长度(高字节在前)
int length = 6; // 设备地址 + 功能码 + 起始地址 + 数据值
baos.write((length >> 8) & 0xFF);
baos.write(length & 0xFF);

// 设备地址
baos.write(deviceAddress);

// 功能码
baos.write(functionCode);

// 起始地址(高字节在前)
baos.write((startAddress >> 8) & 0xFF);
baos.write(startAddress & 0xFF);

// 写入数据
if (dataValue instanceof Integer) {
int value = (Integer) dataValue;
baos.write((value >> 8) & 0xFF);
baos.write(value & 0xFF);
} else if (dataValue instanceof Boolean) {
boolean value = (Boolean) dataValue;
baos.write(value ? 0xFF : 0x00);
baos.write(0x00);
}

return baos.toByteArray();

} catch (Exception e) {
logger.error("构建TCP写入请求帧异常", e);
return new byte[0];
}
}

/**
* 发送请求
* @param requestFrame 请求帧
*/
private void sendRequest(byte[] requestFrame) throws Exception {
if (outputStream != null) {
outputStream.write(requestFrame);
outputStream.flush();
}
}

/**
* 接收响应
* @return 响应帧
*/
private byte[] receiveResponse() throws Exception {
if (inputStream != null) {
// 读取MBAP头(7字节)
byte[] mbapHeader = new byte[7];
inputStream.readFully(mbapHeader);

// 获取数据长度
int dataLength = ((mbapHeader[4] & 0xFF) << 8) | (mbapHeader[5] & 0xFF);

// 读取数据部分
byte[] data = new byte[dataLength];
inputStream.readFully(data);

// 组合完整响应
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(mbapHeader);
baos.write(data);

return baos.toByteArray();
}

return new byte[0];
}

/**
* 解析TCP响应
* @param responseFrame 响应帧
* @param functionCode 功能码
* @return 解析结果
*/
private ModbusReadResult parseTcpResponse(byte[] responseFrame, int functionCode) {
try {
if (responseFrame.length < 9) {
return null;
}

ModbusReadResult result = new ModbusReadResult();
result.setFunctionCode(functionCode);

// 解析数据
if (functionCode == 0x01 || functionCode == 0x02) {
// 读取线圈状态
int byteCount = responseFrame[8] & 0xFF;
byte[] data = new byte[byteCount];
System.arraycopy(responseFrame, 9, data, 0, byteCount);
result.setData(data);
} else if (functionCode == 0x03 || functionCode == 0x04) {
// 读取保持寄存器
int byteCount = responseFrame[8] & 0xFF;
byte[] data = new byte[byteCount];
System.arraycopy(responseFrame, 9, data, 0, byteCount);
result.setData(data);
}

result.setSuccess(true);
result.setRawData(responseFrame);

return result;

} catch (Exception e) {
logger.error("解析TCP响应异常", e);
return null;
}
}

/**
* 解析TCP写入响应
* @param responseFrame 响应帧
* @param functionCode 功能码
* @return 解析结果
*/
private ModbusWriteResult parseTcpWriteResponse(byte[] responseFrame, int functionCode) {
try {
if (responseFrame.length < 9) {
return null;
}

ModbusWriteResult result = new ModbusWriteResult();
result.setFunctionCode(functionCode);

result.setSuccess(true);

return result;

} catch (Exception e) {
logger.error("解析TCP写入响应异常", e);
return null;
}
}

/**
* 检查连接状态
* @return 是否连接
*/
private boolean isConnected() {
return socket != null && !socket.isClosed() && socket.isConnected();
}
}

3.3 Modbus设备管理服务

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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/**
* Modbus设备管理服务
* @author 运维实战
*/
@Service
public class ModbusDeviceService {

@Autowired
private ModbusProperties properties;

@Autowired
private ModbusMonitorService modbusMonitorService;

private final Map<Integer, ModbusDevice> deviceMap = new ConcurrentHashMap<>();
private final Map<Integer, Long> deviceLastCommunicationTime = new ConcurrentHashMap<>();

private static final Logger logger = LoggerFactory.getLogger(ModbusDeviceService.class);

/**
* 注册Modbus设备
* @param deviceId 设备ID
* @param deviceName 设备名称
* @param deviceAddress 设备地址
* @param deviceType 设备类型
* @return 注册结果
*/
public ModbusDeviceRegistrationResult registerDevice(String deviceId, String deviceName, int deviceAddress, String deviceType) {
logger.info("注册Modbus设备,设备ID: {}, 设备地址: {}", deviceId, deviceAddress);

ModbusDeviceRegistrationResult result = new ModbusDeviceRegistrationResult();
result.setDeviceId(deviceId);
result.setDeviceAddress(deviceAddress);
result.setStartTime(System.currentTimeMillis());

try {
// 检查设备是否已注册
if (deviceMap.containsKey(deviceAddress)) {
result.setSuccess(false);
result.setError("设备地址已存在");
result.setEndTime(System.currentTimeMillis());
return result;
}

// 创建设备
ModbusDevice device = new ModbusDevice(deviceId, deviceName, deviceAddress);
device.setDeviceType(deviceType);
device.setDeviceStatus("ACTIVE");
device.setConnectionStatus("CONNECTED");

// 存储设备
deviceMap.put(deviceAddress, device);
deviceLastCommunicationTime.put(deviceAddress, System.currentTimeMillis());

result.setSuccess(true);
result.setDevice(device);
result.setEndTime(System.currentTimeMillis());

logger.info("Modbus设备注册成功,设备ID: {}, 设备地址: {}, 耗时: {}ms",
deviceId, deviceAddress, result.getDuration());

return result;

} catch (Exception e) {
logger.error("Modbus设备注册异常,设备ID: {}", deviceId, e);
result.setSuccess(false);
result.setError("Modbus设备注册异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());
return result;
}
}

/**
* 获取设备
* @param deviceAddress 设备地址
* @return 设备
*/
public ModbusDevice getDevice(int deviceAddress) {
try {
return deviceMap.get(deviceAddress);
} catch (Exception e) {
logger.error("获取Modbus设备异常,设备地址: {}", deviceAddress, e);
return null;
}
}

/**
* 更新设备通信统计
* @param deviceAddress 设备地址
* @param success 是否成功
*/
public void updateDeviceCommunicationStats(int deviceAddress, boolean success) {
try {
ModbusDevice device = deviceMap.get(deviceAddress);
if (device != null) {
device.updateCommunicationStats(success);
deviceLastCommunicationTime.put(deviceAddress, System.currentTimeMillis());

// 更新连接状态
if (success) {
device.setConnectionStatus("CONNECTED");
} else {
device.setConnectionStatus("DISCONNECTED");
}
}
} catch (Exception e) {
logger.error("更新设备通信统计异常,设备地址: {}", deviceAddress, e);
}
}

/**
* 扫描设备
* @return 设备列表
*/
public List<ModbusDevice> scanDevices() {
logger.info("扫描Modbus设备");

List<ModbusDevice> devices = new ArrayList<>();

try {
// 扫描地址范围 1-247
for (int address = 1; address <= 247; address++) {
try {
// 尝试读取设备信息
ModbusDevice device = new ModbusDevice("DEVICE_" + address, "Device " + address, address);
device.setDeviceType("UNKNOWN");
device.setDeviceStatus("ACTIVE");
device.setConnectionStatus("CONNECTED");

devices.add(device);
deviceMap.put(address, device);
deviceLastCommunicationTime.put(address, System.currentTimeMillis());

} catch (Exception e) {
logger.debug("设备地址 {} 无响应", address);
}
}

logger.info("Modbus设备扫描完成,发现设备数量: {}", devices.size());

} catch (Exception e) {
logger.error("Modbus设备扫描异常", e);
}

return devices;
}

/**
* 获取所有设备
* @return 所有设备
*/
public List<ModbusDevice> getAllDevices() {
try {
return new ArrayList<>(deviceMap.values());
} catch (Exception e) {
logger.error("获取所有Modbus设备异常", e);
return new ArrayList<>();
}
}

/**
* 获取在线设备
* @return 在线设备列表
*/
public List<ModbusDevice> getOnlineDevices() {
try {
return deviceMap.values().stream()
.filter(ModbusDevice::isOnline)
.collect(Collectors.toList());
} catch (Exception e) {
logger.error("获取在线Modbus设备异常", e);
return new ArrayList<>();
}
}

/**
* 获取离线设备
* @return 离线设备列表
*/
public List<ModbusDevice> getOfflineDevices() {
try {
return deviceMap.values().stream()
.filter(device -> !device.isOnline())
.collect(Collectors.toList());
} catch (Exception e) {
logger.error("获取离线Modbus设备异常", e);
return new ArrayList<>();
}
}

/**
* 注销设备
* @param deviceAddress 设备地址
* @return 注销结果
*/
public ModbusDeviceUnregistrationResult unregisterDevice(int deviceAddress) {
logger.info("注销Modbus设备,设备地址: {}", deviceAddress);

ModbusDeviceUnregistrationResult result = new ModbusDeviceUnregistrationResult();
result.setDeviceAddress(deviceAddress);
result.setStartTime(System.currentTimeMillis());

try {
// 检查设备是否存在
if (!deviceMap.containsKey(deviceAddress)) {
result.setSuccess(false);
result.setError("设备不存在");
result.setEndTime(System.currentTimeMillis());
return result;
}

// 移除设备
deviceMap.remove(deviceAddress);
deviceLastCommunicationTime.remove(deviceAddress);

result.setSuccess(true);
result.setEndTime(System.currentTimeMillis());

logger.info("Modbus设备注销成功,设备地址: {}, 耗时: {}ms", deviceAddress, result.getDuration());

return result;

} catch (Exception e) {
logger.error("Modbus设备注销异常,设备地址: {}", deviceAddress, e);
result.setSuccess(false);
result.setError("Modbus设备注销异常: " + e.getMessage());
result.setEndTime(System.currentTimeMillis());
return result;
}
}

/**
* 定期更新设备状态
*/
@Scheduled(fixedRate = 30000) // 每30秒更新一次
public void updateDeviceStatus() {
try {
long currentTime = System.currentTimeMillis();

for (Map.Entry<Integer, ModbusDevice> entry : deviceMap.entrySet()) {
int deviceAddress = entry.getKey();
ModbusDevice device = entry.getValue();

Long lastCommunicationTime = deviceLastCommunicationTime.get(deviceAddress);
if (lastCommunicationTime != null) {
long timeSinceLastCommunication = currentTime - lastCommunicationTime;

if (timeSinceLastCommunication > properties.getDeviceOfflineAlertThreshold()) {
device.setConnectionStatus("OFFLINE");
device.setDeviceStatus("OFFLINE");
} else {
device.setConnectionStatus("CONNECTED");
device.setDeviceStatus("ACTIVE");
}
}
}

} catch (Exception e) {
logger.error("更新设备状态异常", e);
}
}
}

3.4 Modbus监控服务

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
/**
* Modbus监控服务
* @author 运维实战
*/
@Service
public class ModbusMonitorService {

private final AtomicLong totalModbusReads = new AtomicLong(0);
private final AtomicLong totalModbusWrites = new AtomicLong(0);
private final AtomicLong totalSuccessfulReads = new AtomicLong(0);
private final AtomicLong totalFailedReads = new AtomicLong(0);
private final AtomicLong totalSuccessfulWrites = new AtomicLong(0);
private final AtomicLong totalFailedWrites = new AtomicLong(0);
private final AtomicLong totalBatchReads = new AtomicLong(0);
private final AtomicLong totalBatchReadSuccesses = new AtomicLong(0);

private long lastResetTime = System.currentTimeMillis();
private final long resetInterval = 300000; // 5分钟重置一次

private static final Logger logger = LoggerFactory.getLogger(ModbusMonitorService.class);

/**
* 记录Modbus读取
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param success 是否成功
*/
public void recordModbusRead(int deviceAddress, int functionCode, boolean success) {
totalModbusReads.incrementAndGet();

if (success) {
totalSuccessfulReads.incrementAndGet();
} else {
totalFailedReads.incrementAndGet();
}

logger.debug("记录Modbus读取: 设备地址={}, 功能码={}, 成功={}", deviceAddress, functionCode, success);
}

/**
* 记录Modbus写入
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param success 是否成功
*/
public void recordModbusWrite(int deviceAddress, int functionCode, boolean success) {
totalModbusWrites.incrementAndGet();

if (success) {
totalSuccessfulWrites.incrementAndGet();
} else {
totalFailedWrites.incrementAndGet();
}

logger.debug("记录Modbus写入: 设备地址={}, 功能码={}, 成功={}", deviceAddress, functionCode, success);
}

/**
* 记录Modbus批量读取
* @param totalCount 总数量
* @param successCount 成功数量
*/
public void recordModbusBatchRead(int totalCount, int successCount) {
totalBatchReads.addAndGet(totalCount);
totalBatchReadSuccesses.addAndGet(successCount);

logger.debug("记录Modbus批量读取: 总数={}, 成功={}", totalCount, successCount);
}

/**
* 获取监控指标
* @return 监控指标
*/
public ModbusMetrics getMetrics() {
// 检查是否需要重置
if (System.currentTimeMillis() - lastResetTime > resetInterval) {
resetMetrics();
}

ModbusMetrics metrics = new ModbusMetrics();
metrics.setTotalModbusReads(totalModbusReads.get());
metrics.setTotalModbusWrites(totalModbusWrites.get());
metrics.setTotalSuccessfulReads(totalSuccessfulReads.get());
metrics.setTotalFailedReads(totalFailedReads.get());
metrics.setTotalSuccessfulWrites(totalSuccessfulWrites.get());
metrics.setTotalFailedWrites(totalFailedWrites.get());
metrics.setTotalBatchReads(totalBatchReads.get());
metrics.setTotalBatchReadSuccesses(totalBatchReadSuccesses.get());
metrics.setTimestamp(System.currentTimeMillis());

return metrics;
}

/**
* 重置指标
*/
private void resetMetrics() {
totalModbusReads.set(0);
totalModbusWrites.set(0);
totalSuccessfulReads.set(0);
totalFailedReads.set(0);
totalSuccessfulWrites.set(0);
totalFailedWrites.set(0);
totalBatchReads.set(0);
totalBatchReadSuccesses.set(0);
lastResetTime = System.currentTimeMillis();

logger.info("Modbus监控指标重置");
}

/**
* 定期监控Modbus状态
*/
@Scheduled(fixedRate = 30000) // 每30秒监控一次
public void monitorModbusStatus() {
try {
ModbusMetrics metrics = getMetrics();

logger.info("Modbus监控: 读取={}, 写入={}, 读取成功={}, 读取失败={}, 写入成功={}, 写入失败={}, 批量读取={}, 批量成功={}, 读取成功率={}%, 写入成功率={}%, 批量读取成功率={}%",
metrics.getTotalModbusReads(), metrics.getTotalModbusWrites(),
metrics.getTotalSuccessfulReads(), metrics.getTotalFailedReads(),
metrics.getTotalSuccessfulWrites(), metrics.getTotalFailedWrites(),
metrics.getTotalBatchReads(), metrics.getTotalBatchReadSuccesses(),
String.format("%.2f", metrics.getReadSuccessRate()),
String.format("%.2f", metrics.getWriteSuccessRate()),
String.format("%.2f", metrics.getBatchReadSuccessRate()));

// 检查异常情况
if (metrics.getReadSuccessRate() < 95) {
logger.warn("Modbus读取成功率过低: {}%", String.format("%.2f", metrics.getReadSuccessRate()));
}

if (metrics.getWriteSuccessRate() < 90) {
logger.warn("Modbus写入成功率过低: {}%", String.format("%.2f", metrics.getWriteSuccessRate()));
}

if (metrics.getBatchReadSuccessRate() < 85) {
logger.warn("Modbus批量读取成功率过低: {}%", String.format("%.2f", metrics.getBatchReadSuccessRate()));
}

} catch (Exception e) {
logger.error("Modbus状态监控失败", e);
}
}
}

3.5 Modbus指标类

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
/**
* Modbus指标类
* @author 运维实战
*/
@Data
public class ModbusMetrics {

private long totalModbusReads;
private long totalModbusWrites;
private long totalSuccessfulReads;
private long totalFailedReads;
private long totalSuccessfulWrites;
private long totalFailedWrites;
private long totalBatchReads;
private long totalBatchReadSuccesses;
private long timestamp;

public ModbusMetrics() {
this.timestamp = System.currentTimeMillis();
}

/**
* 获取读取成功率
* @return 读取成功率
*/
public double getReadSuccessRate() {
long total = totalSuccessfulReads + totalFailedReads;
if (total == 0) return 0.0;
return (double) totalSuccessfulReads / total * 100;
}

/**
* 获取读取失败率
* @return 读取失败率
*/
public double getReadFailureRate() {
long total = totalSuccessfulReads + totalFailedReads;
if (total == 0) return 0.0;
return (double) totalFailedReads / total * 100;
}

/**
* 获取写入成功率
* @return 写入成功率
*/
public double getWriteSuccessRate() {
long total = totalSuccessfulWrites + totalFailedWrites;
if (total == 0) return 0.0;
return (double) totalSuccessfulWrites / total * 100;
}

/**
* 获取写入失败率
* @return 写入失败率
*/
public double getWriteFailureRate() {
long total = totalSuccessfulWrites + totalFailedWrites;
if (total == 0) return 0.0;
return (double) totalFailedWrites / total * 100;
}

/**
* 获取批量读取成功率
* @return 批量读取成功率
*/
public double getBatchReadSuccessRate() {
if (totalBatchReads == 0) return 0.0;
return (double) totalBatchReadSuccesses / totalBatchReads * 100;
}

/**
* 获取读取效率
* @return 读取效率
*/
public double getReadEfficiency() {
if (totalModbusReads == 0) return 0.0;
return (double) totalSuccessfulReads / totalModbusReads * 100;
}

/**
* 获取写入效率
* @return 写入效率
*/
public double getWriteEfficiency() {
if (totalModbusWrites == 0) return 0.0;
return (double) totalSuccessfulWrites / totalModbusWrites * 100;
}

/**
* 是否健康
* @return 是否健康
*/
public boolean isHealthy() {
return getReadSuccessRate() > 95 &&
getWriteSuccessRate() > 90 &&
getBatchReadSuccessRate() > 85;
}
}

4. Modbus控制器

4.1 Modbus REST控制器

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
/**
* Modbus REST控制器
* @author 运维实战
*/
@RestController
@RequestMapping("/api/modbus")
public class ModbusController {

@Autowired
private ModbusService modbusService;

@Autowired
private ModbusMonitorService modbusMonitorService;

private static final Logger logger = LoggerFactory.getLogger(ModbusController.class);

/**
* 读取Modbus数据
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataLength 数据长度
* @return 读取结果
*/
@GetMapping("/read")
public ResponseEntity<ModbusReadResult> readModbusData(
@RequestParam int deviceAddress,
@RequestParam int functionCode,
@RequestParam int startAddress,
@RequestParam int dataLength) {
try {
logger.info("接收到Modbus数据读取请求,设备地址: {}, 功能码: {}", deviceAddress, functionCode);

ModbusReadResult result = modbusService.readModbusData(deviceAddress, functionCode, startAddress, dataLength);

return ResponseEntity.ok(result);

} catch (Exception e) {
logger.error("Modbus数据读取失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}

/**
* 写入Modbus数据
* @param deviceAddress 设备地址
* @param functionCode 功能码
* @param startAddress 起始地址
* @param dataValue 数据值
* @return 写入结果
*/
@PostMapping("/write")
public ResponseEntity<ModbusWriteResult> writeModbusData(
@RequestParam int deviceAddress,
@RequestParam int functionCode,
@RequestParam int startAddress,
@RequestBody Object dataValue) {
try {
logger.info("接收到Modbus数据写入请求,设备地址: {}, 功能码: {}", deviceAddress, functionCode);

ModbusWriteResult result = modbusService.writeModbusData(deviceAddress, functionCode, startAddress, dataValue);

return ResponseEntity.ok(result);

} catch (Exception e) {
logger.error("Modbus数据写入失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}

/**
* 批量读取Modbus数据
* @param readRequests 读取请求列表
* @return 批量读取结果
*/
@PostMapping("/batch-read")
public ResponseEntity<ModbusBatchReadResult> batchReadModbusData(@RequestBody List<ModbusReadRequest> readRequests) {
try {
logger.info("接收到Modbus数据批量读取请求,请求数量: {}", readRequests.size());

ModbusBatchReadResult result = modbusService.batchReadModbusData(readRequests);

return ResponseEntity.ok(result);

} catch (Exception e) {
logger.error("Modbus数据批量读取失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}

/**
* 获取Modbus设备信息
* @param deviceAddress 设备地址
* @return 设备信息
*/
@GetMapping("/device/{deviceAddress}")
public ResponseEntity<ModbusDevice> getModbusDevice(@PathVariable int deviceAddress) {
try {
logger.info("接收到获取Modbus设备信息请求,设备地址: {}", deviceAddress);

ModbusDevice device = modbusService.getModbusDevice(deviceAddress);

return ResponseEntity.ok(device);

} catch (Exception e) {
logger.error("获取Modbus设备信息失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}

/**
* 扫描Modbus设备
* @return 扫描结果
*/
@PostMapping("/scan")
public ResponseEntity<ModbusScanResult> scanModbusDevices() {
try {
logger.info("接收到Modbus设备扫描请求");

ModbusScanResult result = modbusService.scanModbusDevices();

return ResponseEntity.ok(result);

} catch (Exception e) {
logger.error("Modbus设备扫描失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}

/**
* 获取Modbus监控指标
* @return 监控指标
*/
@GetMapping("/metrics")
public ResponseEntity<ModbusMetrics> getModbusMetrics() {
try {
ModbusMetrics metrics = modbusMonitorService.getMetrics();
return ResponseEntity.ok(metrics);
} catch (Exception e) {
logger.error("获取Modbus监控指标失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}

5. 总结

5.1 Modbus最佳实践

  1. 合理选择通信模式: 根据应用场景选择合适的通信模式(RTU、ASCII、TCP)
  2. 优化通信参数: 合理设置通信超时、重试次数等参数
  3. 实现设备管理: 建立完善的设备管理和监控机制
  4. 异常处理: 实现完善的异常处理和用户友好提示
  5. 性能监控: 实时监控Modbus通信性能

5.2 性能优化建议

  • 通信优化: 优化通信参数和协议设置
  • 批量操作: 使用批量读取减少通信次数
  • 缓存策略: 实现合理的数据缓存策略
  • 连接管理: 优化TCP连接管理
  • 错误处理: 完善错误处理和重试机制

5.3 运维管理要点

  • 实时监控: 监控Modbus通信状态和性能
  • 设备管理: 建立完善的设备注册、发现、管理机制
  • 故障诊断: 实现故障诊断和自动恢复
  • 日志管理: 完善日志记录和分析
  • 性能调优: 根据监控数据优化Modbus性能

通过本文的Modbus运维实战指南,您可以掌握Modbus协议的原理、实现方法、性能优化技巧以及在企业级应用中的最佳实践,构建高效、可靠的Modbus通信系统!