适用场景:工业物联网(IIoT)、PLC采集、2000+设备高并发轮询
一、方案概述
本方案基于 Netty NIO 与 modbus4j 库,构建高性能、低延迟的 Modbus RTU over TCP 通信系统。
核心设计思想
| 层级 | 职责 |
|---|---|
| Netty | IO 多路复用、拆包、连接管理、调度 |
| modbus4j | 协议解析、CRC校验、功能码语义 |
| 业务层 | 数据持久化、告警、计算 |
✅ 单一职责
✅ 无阻塞 IO
✅ 毫秒级轮询
✅ 线性扩展
二、系统架构
┌──────────────────────────────┐
│ Business Layer │ ← 数据库 / MQ / 告警
└─────────────▲────────────────┘
│ ChannelHandler
┌─────────────┴────────────────┐
│ StateMachineHandler │ ← 请求-响应对齐
├──────────────────────────────┤
│ ModbusParseHandler │ ← modbus4j 解析
├──────────────────────────────┤
│ ModbusRtuDecoder │ ← 拆包 + CRC
├──────────────────────────────┤
│ IdleStateHandler │ ← 心跳/断连
└─────────────▲────────────────┘
│ Socket
┌─────────────┴────────────────┐
│ TCP Device │
│ (串口服务器/网关) │
└──────────────────────────────┘
三、核心技术选型
| 组件 | 选型 | 原因 |
|---|---|---|
| IO框架 | Netty 4.1.x | 高性能、成熟 |
| 协议解析 | modbus4j | 工业验证 |
| 定时器 | HashedWheelTimer | O(1) 轮询 |
| 线程模型 | EventLoopGroup | 非阻塞 |
| 序列化 | ByteBuf | 零拷贝 |
四、核心模块设计
4.1 服务启动(ServerBootstrap)
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(boss, worker)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline()
.addLast(new IdleStateHandler(5, 0, 0))
.addLast(new ModbusRtuDecoder())
.addLast(new ModbusParseHandler())
.addLast(new StateMachineHandler())
.addLast(new BusinessHandler());
}
});
b.bind(9090).sync();
4.2 拆包层(ModbusRtuDecoder)
✅ 只负责拿到完整 RTU 帧
- 最小 4 字节
- CRC 校验
- 功能码长度预判
📌 不解析寄存器
4.3 协议解析层(ModbusParseHandler)
public class ModbusParseHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
byte[] frame = (byte[]) msg;
ModbusResponse resp = ModbusRtuUtils.parseResponse(frame);
ctx.fireChannelRead(resp);
}
}
✅ modbus4j 自动完成:
- CRC
- 异常码
- 字节序
4.4 状态机层(StateMachineHandler)
| 状态 | 行为 |
|---|---|
| IDLE | 允许发送 |
| WAIT_RESPONSE | 拒绝新请求 |
| TIMEOUT | 关闭连接 |
✅ 防止 RTU 乱序
4.5 轮询调度(HashedWheelTimer)
HashedWheelTimer timer =
new HashedWheelTimer(100, MILLISECONDS, 512);
void schedule(Channel ch, int slaveId) {
timer.newTimeout(t -> {
if (!ch.isActive()) return;
ModbusRequest req =
new ReadHoldingRegistersRequest(slaveId, 0, 10);
ch.writeAndFlush(req);
schedule(ch, slaveId);
}, 1, SECONDS);
}
✅ 天然背压控制
五、业务处理示例
protected void channelRead0(ChannelHandlerContext ctx,
ModbusResult result) {
ReadResponse resp = result.response();
int status = resp.getShort(0);
float temp = resp.getFloat(2);
long ts = System.currentTimeMillis();
businessExecutor.execute(() ->
repository.save(status, temp, ts)
);
}
⚠️ 严禁阻塞 EventLoop
六、性能与稳定性设计
6.1 线程模型
| 线程 | 职责 |
|---|---|
| Boss | Accept |
| Worker | IO |
| Business | DB / MQ |
6.2 高并发优化
✅ 单连接串行轮询
✅ 无锁状态机
✅ ByteBuf 零拷贝
✅ 定时器 O(1)
6.3 容错机制
| 场景 | 策略 |
|---|---|
| CRC 错误 | 丢弃 + 断连 |
| 超时 | 关闭连接 |
| 乱序 | 丢弃 |
| OOM | 池化 ByteBuf |
七、部署建议
| 规模 | 配置 |
|---|---|
| ≤500 设备 | 单节点 |
| 500~2000 | 多端口 |
| ≥2000 | 多实例 + 网关分组 |
八、与手写 NIO 对比
| 指标 | 手写 NIO | Netty |
|---|---|---|
| 开发周期 | 高 | 低 |
| Bug 率 | 高 | 极低 |
| 维护成本 | 高 | 低 |
| 吞吐量 | 中 | 极高 |
九、总结
Netty 负责“快”,modbus4j 负责“准”。
该方案已在工业现场验证,适用于:
- 电力监控
- 智能制造
- 能源采集
- 智慧水务
十、下一步可选交付
✅ 封装 Modbus RTU ↔ Netty Adapter
✅ 多 Slave 轮询模板
✅ 断线重连与黑名单机制
✅ Prometheus 监控指标