Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
Z
zhmes-agecal
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
耿迪迪
zhmes-agecal
Commits
9406e0a9
Commit
9406e0a9
authored
Sep 24, 2025
by
wanghao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1 测试 上电后通信 和 最终完成 定时任务功能
parent
f5156dc3
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
66 additions
and
36 deletions
+66
-36
DeviceStatusReaderAndTimeSetter.java
...stem/modbus/business/DeviceStatusReaderAndTimeSetter.java
+66
-36
No files found.
zhmes-agecal-system/src/main/java/com/zehong/system/modbus/business/DeviceStatusReaderAndTimeSetter.java
View file @
9406e0a9
...
...
@@ -171,39 +171,73 @@ public class DeviceStatusReaderAndTimeSetter {
TcpMaster
tcpMaster
=
(
TcpMaster
)
master
;
try
{
// 1. 获取TcpMaster的private字段"transport"(类型:TcpTransport)
// 1. 关键:内部类路径用 "$" 连接外部类(必须与你的Modbus4j版本匹配)
String
transportClassName
=
"sun.rmi.transport.tcp.TcpTransport"
;
Class
<?>
transportClass
=
Class
.
forName
(
transportClassName
);
log
.
debug
(
"成功加载TcpMaster内部类:{}"
,
transportClassName
);
// 2. 获取TcpMaster的private字段 "transport"(存储内部类实例)
Field
transportField
=
TcpMaster
.
class
.
getDeclaredField
(
"transport"
);
transportField
.
setAccessible
(
true
);
// 取消私有字段访问
检查
transportField
.
setAccessible
(
true
);
// 取消私有字段访问
限制
Object
transport
=
transportField
.
get
(
tcpMaster
);
if
(
transport
==
null
)
{
log
.
error
(
"TcpMaster的transport字段为null"
);
log
.
error
(
"TcpMaster的transport字段为null
(连接未初始化?)
"
);
return
null
;
}
// 2. 获取TcpTransport的private字段"socket"(类型:Socket)
// 注意:TcpTransport是Modbus4j的内部类,包路径为com.serotonin.modbus4j.ip.tcp.TcpTransport
Class
<?>
transportClass
=
Class
.
forName
(
"com.serotonin.modbus4j.ip.tcp.TcpTransport"
);
// 3. 获取内部类TcpTransport的private字段 "socket"(底层Socket)
// 注意:若报错"NoSuchFieldException",需打开Modbus4j源码确认字段名(如"clientSocket")
Field
socketField
=
transportClass
.
getDeclaredField
(
"socket"
);
socketField
.
setAccessible
(
true
);
// 取消私有字段访问
检查
socketField
.
setAccessible
(
true
);
// 取消私有字段访问
限制
Socket
socket
=
(
Socket
)
socketField
.
get
(
transport
);
log
.
debug
(
"成功获取Socket:
{}"
,
socket
);
log
.
debug
(
"成功获取Socket:
IP={}, 本地端口={}"
,
socket
.
getInetAddress
(),
socket
.
getLocalPort
()
);
return
socket
;
}
catch
(
ClassNotFoundException
e
)
{
log
.
error
(
"=== 致命错误:TcpTransport类未找到!===\n"
+
"原因:1. Modbus4j版本不兼容;2. 内部类路径错误(需确认是否为 TcpMaster$TcpTransport)\n"
+
"解决方案:1. 打开Modbus4j源码,找到TcpMaster的内部类TcpTransport,复制完整类名;\n"
+
" 2. 将 transportClassName 改为实际路径(如 com.xxx.TcpMaster$TcpTransport)"
,
e
);
}
catch
(
NoSuchFieldException
e
)
{
log
.
error
(
"反射获取字段失败(可能Modbus4j版本不兼容),请检查字段名"
,
e
);
log
.
error
(
"=== 致命错误:字段未找到!===\n"
+
"原因:1. TcpMaster的transport字段名错误;2. TcpTransport的socket字段名错误\n"
+
"解决方案:1. 打开TcpMaster源码,确认传输字段名(如'tcpTransport');\n"
+
" 2. 打开TcpTransport源码,确认Socket字段名(如'clientSocket')"
,
e
);
}
catch
(
IllegalAccessException
e
)
{
log
.
error
(
"反射访问字段权限失败"
,
e
);
}
catch
(
ClassNotFoundException
e
)
{
log
.
error
(
"TcpTransport类未找到(Modbus4j版本不兼容)"
,
e
);
log
.
error
(
"反射访问字段权限失败(可能被安全管理器拦截)"
,
e
);
}
catch
(
Exception
e
)
{
log
.
error
(
"获取底层Socket异常"
,
e
);
}
return
null
;
}
/**
* 销毁ModbusMaster并关闭底层Socket(确保资源彻底释放)
*/
private
static
void
destroyModbusMaster
(
ModbusMaster
master
,
int
deviceId
)
{
if
(
master
==
null
)
return
;
try
{
// 1. 先关闭底层Socket(反射获取)
Socket
socket
=
getUnderlyingSocket
(
master
);
if
(
socket
!=
null
&&
!
socket
.
isClosed
())
{
socket
.
close
();
log
.
debug
(
"设备{}: 底层Socket已强制关闭"
,
deviceId
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
"设备{}: 关闭底层Socket异常"
,
deviceId
,
e
);
}
finally
{
// 2. 再销毁ModbusMaster
try
{
master
.
destroy
();
log
.
debug
(
"设备{}: ModbusMaster已销毁"
,
deviceId
);
}
catch
(
Exception
e
)
{
log
.
error
(
"设备{}: 销毁ModbusMaster异常"
,
deviceId
,
e
);
}
}
}
/**
* 启动多设备监控(
无反射,兼容所有版本
)
* 启动多设备监控(
反射方案,确保资源释放
)
*/
public
void
startMultiDeviceMonitoring
(
String
ip
,
int
port
,
List
<
Integer
>
deviceIds
,
...
...
@@ -215,7 +249,7 @@ public class DeviceStatusReaderAndTimeSetter {
}
final
CountDownLatch
latch
=
new
CountDownLatch
(
deviceIds
.
size
());
log
.
info
(
"开始监控设备:IP={}, 端口={}, 设备数={}(活跃线程:{})"
,
log
.
info
(
"开始监控设备:IP={}, 端口={}, 设备数={}(
线程池
活跃线程:{})"
,
ip
,
port
,
deviceIds
.
size
(),
((
ThreadPoolExecutor
)
FIXED_THREAD_POOL
).
getActiveCount
());
for
(
int
deviceId
:
deviceIds
)
{
...
...
@@ -223,60 +257,56 @@ public class DeviceStatusReaderAndTimeSetter {
FIXED_THREAD_POOL
.
submit
(()
->
{
ModbusMaster
threadMaster
=
null
;
try
{
// 1. 创建
连接(每次任务独立连接,避免复用导致
泄漏)
// 1. 创建
独立连接(每个设备任务一个连接,避免复用
泄漏)
threadMaster
=
createModbusMaster
(
ip
,
port
);
if
(
threadMaster
==
null
)
{
log
.
error
(
"设备{}: Modbus连接创建失败"
,
devId
);
log
.
error
(
"设备{}: Modbus连接创建失败
,终止任务
"
,
devId
);
recordAlarm
(
"03"
,
"ip:"
+
ip
+
",port:"
+
port
+
",deviceId:"
+
devId
,
"连接创建失败"
);
return
;
}
// 2. 读取数据(带
超时控制的重试
)
// 2. 读取数据(带
重试和异常处理
)
int
[]
result
=
readWithConditionalRetry
(
threadMaster
,
ip
,
port
,
devId
,
stopCondition
);
// 3.
处理结果
// 3.
回调处理结果(判空避免NPE)
if
(
resultHandler
!=
null
)
{
resultHandler
.
accept
(
new
DeviceStatusReaderDto
(
ip
,
port
,
devId
,
result
));
}
}
catch
(
ModbusInitException
e
)
{
log
.
error
(
"设备{}: Modbus连接初始化失败"
,
devId
,
e
);
recordAlarm
(
"03"
,
"ip:"
+
ip
+
",port:"
+
port
+
",deviceId:"
+
devId
,
"连接初始化失败:"
+
e
.
getMessage
());
recordAlarm
(
"03"
,
"ip:"
+
ip
+
",port:"
+
port
+
",deviceId:"
+
devId
,
"连接初始化失败:"
+
e
.
getMessage
());
}
catch
(
Throwable
e
)
{
log
.
error
(
"设备{}: 监控任务异常"
,
devId
,
e
);
String
alarmMsg
=
"监控任务异常:"
+
e
.
getMessage
();
log
.
error
(
"设备{}: 监控任务
致命
异常"
,
devId
,
e
);
String
alarmMsg
=
e
instanceof
OutOfMemoryError
?
"内存溢出:"
+
e
.
getMessage
()
:
"监控任务异常:"
+
e
.
getMessage
();
recordAlarm
(
"03"
,
"ip:"
+
ip
+
",port:"
+
port
+
",deviceId:"
+
devId
,
alarmMsg
);
}
finally
{
// 关键:优先销毁连接,确保资源释放(兼容所有版本)
if
(
threadMaster
!=
null
)
{
try
{
threadMaster
.
destroy
();
log
.
debug
(
"设备{}: Modbus连接已销毁"
,
devId
);
}
catch
(
Exception
e
)
{
log
.
error
(
"设备{}: Modbus连接销毁失败"
,
devId
,
e
);
}
}
// 关键:无论成功/失败,都强制销毁连接(避免资源泄漏)
destroyModbusMaster
(
threadMaster
,
devId
);
latch
.
countDown
();
log
.
info
(
"设备{}: 监控任务完成(剩余任务:{})"
,
devId
,
latch
.
getCount
());
}
});
}
// 等待
任务完成,超时后记录告警
// 等待
所有任务完成,超时后强制中断(避免长期阻塞)
try
{
if
(!
latch
.
await
(
TIMEOUT_SECONDS
,
TimeUnit
.
SECONDS
))
{
log
.
warn
(
"IP{}: 部分设备监控超时(未完成:{})"
,
ip
,
latch
.
getCount
());
recordAlarm
(
"03"
,
"ip:"
+
ip
+
",port:"
+
port
,
"部分设备监控超时(未完成:"
+
latch
.
getCount
()
+
")"
);
// 超时后主动关闭所有线程池任务(避免长期阻塞)
log
.
warn
(
"IP{}: 部分设备监控超时(未完成任务数:{}),强制中断"
,
ip
,
latch
.
getCount
());
recordAlarm
(
"03"
,
"ip:"
+
ip
+
",port:"
+
port
,
"部分设备监控超时(未完成:"
+
latch
.
getCount
()
+
")"
);
// 超时后关闭线程池(避免任务堆积)
FIXED_THREAD_POOL
.
shutdownNow
();
}
}
catch
(
InterruptedException
e
)
{
log
.
error
(
"IP{}: 监控任务被中断"
,
ip
,
e
);
Thread
.
currentThread
().
interrupt
();
Thread
.
currentThread
().
interrupt
();
// 恢复中断状态
}
}
/**
* 统一告警记录(抽离避免重复代码)
*/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment