最近把一个压箱底的项目开源了:njs-modbus,一个零依赖、strict TypeScript 的 Node.js Modbus 协议栈,支持 TCP / RTU / ASCII / UDP / TLS 。
先上链接:
- GitHub: https://github.com/xiejay97/njs-modbus
- 深度介绍(中文版):README.zh-CN.md
为什么又要造轮子?
在 IIoT 边缘干了十多年,被各种 Modbus 库坑惨了:
- GC 一抖,100 ms 轮询变 300 ms ,PLC 直接报警;
- 帧边界全靠"睡一会儿再读",产线 EMI 一来就粘包断包;
- 每个请求 new 对象,几千点并发时 Node.js GC 过山车;
- 安全策略等于"端口不外开",真放 DMZ 里连白名单都没有。
大多数 Node.js Modbus 库没把自己当成工业软件写。所以我们决定自己写一个:运行时零依赖、strict TypeScript ,从第一行代码就按产线标准来。
几个我们觉得不一样的地方
1. 热路径真的在抠微秒
- TCP 编解码约 0.11 µs,RTU 约 0.12 µs,ASCII 约 0.13 µs;
- 解码路径 gc_ns_per_op = 0,不分配对象;
- Queue 用七个平行原始类型数组 + head index ,拒绝
Array.shift()。
不是炫技,是现场 P99 真的会被这些小地方吃掉。
2. 韧性不是边缘补丁
我们做了混沌测试:截断帧、粘包、垃圾字节、CRC 篡改、超长帧。结果是 TCP/RTU/ASCII 全过,而同类库在 RTU 上只有 8/12 和 3/12 。
更具体一点:噪声过去后,TCP 模式下约 270 µs、RTU 模式下约 850 µs 就能重新锁定下一帧头部,不销毁连接、不重启实例。
3. Transport-agnostic 是真的
Pipeline 层就一个薄接口:
interface AbstractPipelineAdapter {
write(data: Buffer, cb?: (err?: Error) => void): void
on(event: 'data', listener: (data: Buffer) => void): this
}
TCP 、TLS 、UDP 、Serial 、WebSocket 、你自己的硬件抽象,都能接。示例里 WebSocket Pipeline 只写了 133 行。
4. 安全不是"端口不外开"
- 三关鉴权:unit 、address 、runtime ;
- 连接级:IP 白名单(精确/CIDR/自定义 predicate )、maxConnections 、maxConnectionsPerIp 、idleTimeout ;
- 原生 TLS ,含 mutual TLS ;
- 所有拒绝都生成结构化 audit log ,可直接打 SIEM 。
想聊的
- 大家在工业现场用 Node.js 做 Modbus 主站/从站,最怕遇到什么问题?
- 你们觉得一个协议栈要做到什么程度,才敢写进给客户的技术方案?
- 严格 TS + 零依赖这条路线,在你们的项目里吃得开吗?
欢迎拍砖,Issue 和 PR 都开放。