njs-modbus 3.2.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +185 -110
- package/README.zh-CN.md +185 -109
- package/dist/index.cjs +1084 -588
- package/dist/index.d.ts +92 -61
- package/dist/index.mjs +1084 -588
- package/dist/utils.cjs +293 -168
- package/dist/utils.d.ts +43 -40
- package/dist/utils.mjs +289 -167
- package/package.json +4 -3
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](./README.md) | 简体中文
|
|
4
4
|
|
|
5
|
-
Node.js 的纯 JavaScript Modbus
|
|
5
|
+
Node.js 的纯 JavaScript Modbus 实现,针对高吞吐量和低 GC 压力优化。
|
|
6
6
|
|
|
7
7
|
<!-- prettier-ignore-start -->
|
|
8
8
|
[](http://www.npm-stats.com/~packages/njs-modbus)
|
|
@@ -11,17 +11,20 @@ Node.js 的纯 JavaScript Modbus 实现。
|
|
|
11
11
|
[](https://github.com/xiejay97/njs-modbus/actions)
|
|
12
12
|
<!-- prettier-ignore-end -->
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## 核心亮点
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
16
|
+
- **协议** — Modbus TCP、RTU、ASCII
|
|
17
|
+
- **传输** — 串口、TCP 客户端/服务端、UDP 客户端/服务端,支持可插拔自定义传输层
|
|
18
|
+
- **性能优先** — 并行 FIFO 队列、惰性删除定时器堆、内联大端读写、零分配热路径
|
|
19
|
+
- **主站** — FIFO 或流水线并发请求(仅 TCP)
|
|
20
|
+
- **从站** — 每连接 FIFO 或并发处理(仅 TCP)
|
|
20
21
|
- **自定义功能码**,支持可插拔帧解析
|
|
21
|
-
-
|
|
22
|
+
- **广播**(`unit = 0`)
|
|
22
23
|
- **完整 TypeScript**
|
|
23
24
|
- **零运行时依赖**(仅在使用串口时 peer-depends `serialport`)
|
|
24
25
|
|
|
26
|
+
## 支持的功能码
|
|
27
|
+
|
|
25
28
|
| 码值 | 名称 |
|
|
26
29
|
|------|------|
|
|
27
30
|
| 01 | 读取线圈 |
|
|
@@ -39,6 +42,8 @@ Node.js 的纯 JavaScript Modbus 实现。
|
|
|
39
42
|
|
|
40
43
|
## 安装
|
|
41
44
|
|
|
45
|
+
需要 **Node.js ≥ 18.19**。
|
|
46
|
+
|
|
42
47
|
```bash
|
|
43
48
|
npm install njs-modbus
|
|
44
49
|
```
|
|
@@ -114,20 +119,45 @@ const master = new ModbusMaster({
|
|
|
114
119
|
});
|
|
115
120
|
```
|
|
116
121
|
|
|
122
|
+
## 架构
|
|
123
|
+
|
|
124
|
+
本库遵循严格的两层设计:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
┌─────────────────────────────────────────┐
|
|
128
|
+
│ ModbusMaster / ModbusSlave │ ← 用户 API,会话/队列管理
|
|
129
|
+
├─────────────────────────────────────────┤
|
|
130
|
+
│ TcpApplicationLayer │ ← 协议帧解析(MBAP / CRC16 / LRC)
|
|
131
|
+
│ RtuApplicationLayer │
|
|
132
|
+
│ AsciiApplicationLayer │
|
|
133
|
+
├─────────────────────────────────────────┤
|
|
134
|
+
│ AbstractPhysicalConnection │ ← 每连接 I/O
|
|
135
|
+
├─────────────────────────────────────────┤
|
|
136
|
+
│ AbstractPhysicalLayer │ ← 资源管理(端口/套接字/服务端)
|
|
137
|
+
│ ├── TcpClientPhysicalLayer │
|
|
138
|
+
│ ├── TcpServerPhysicalLayer │
|
|
139
|
+
│ ├── UdpClientPhysicalLayer │
|
|
140
|
+
│ ├── UdpServerPhysicalLayer │
|
|
141
|
+
│ └── SerialPhysicalLayer │
|
|
142
|
+
└─────────────────────────────────────────┘
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
所有传输层都统一为面向连接的模型:物理层在就绪时触发 `'connect'` 事件并传入一个 `AbstractPhysicalConnection`,每个连接会独立创建一个应用层实例。
|
|
146
|
+
|
|
117
147
|
## 物理层
|
|
118
148
|
|
|
119
|
-
所有物理层暴露 `open()` / `close()`、`state`
|
|
149
|
+
所有物理层暴露 `open()` / `close()`、`state` 属性,以及 [事件](#事件) 章节中列出的事件。
|
|
120
150
|
|
|
121
|
-
| 类型 |
|
|
122
|
-
|
|
123
|
-
| `SERIAL` | `
|
|
124
|
-
| `TCP_CLIENT` | `
|
|
125
|
-
| `TCP_SERVER` | `
|
|
126
|
-
| `UDP_CLIENT` | `
|
|
127
|
-
| `UDP_SERVER` | `
|
|
128
|
-
| `CUSTOM` | *(用户自定义)* |
|
|
151
|
+
| 类型 | `open(...)` 参数 | 说明 |
|
|
152
|
+
|------|-----------------|------|
|
|
153
|
+
| `SERIAL` | `()` | 通过 `serialport` 包访问串口 |
|
|
154
|
+
| `TCP_CLIENT` | `SocketConnectOpts` | TCP 客户端套接字 |
|
|
155
|
+
| `TCP_SERVER` | `ListenOptions` | TCP 服务端 |
|
|
156
|
+
| `UDP_CLIENT` | `{ port?, address? }` | UDP 客户端 |
|
|
157
|
+
| `UDP_SERVER` | `BindOptions` | UDP 服务端 |
|
|
158
|
+
| `CUSTOM` | *(用户自定义)* | 用户提供的 `AbstractPhysicalLayer` 实例 |
|
|
129
159
|
|
|
130
|
-
### 服务端配置
|
|
160
|
+
### TCP 服务端配置
|
|
131
161
|
|
|
132
162
|
```typescript
|
|
133
163
|
const slave = new ModbusSlave({
|
|
@@ -143,62 +173,44 @@ const slave = new ModbusSlave({
|
|
|
143
173
|
});
|
|
144
174
|
```
|
|
145
175
|
|
|
146
|
-
###
|
|
176
|
+
### 物理层选项参考
|
|
147
177
|
|
|
148
178
|
| 选项 | 类型 | 说明 |
|
|
149
|
-
|
|
179
|
+
|------|------|------|
|
|
150
180
|
| `whitelist` | `string[]` | 允许的客户端 IP。`::ffff:` 前缀自动剥离。 |
|
|
151
181
|
| `maxConnections` | `number` | 最大并发连接数。超出后新连接静默丢弃。 |
|
|
152
182
|
| `idleTimeout` | `number` | 空闲超时(毫秒),超时后驱逐连接。默认 `30000`,传 `0` 禁用。 |
|
|
153
183
|
| `socketOpts` / `serverOpts` | `object` | 透传给 Node.js `createSocket()` / `createServer()`。 |
|
|
154
184
|
|
|
155
|
-
##
|
|
156
|
-
|
|
157
|
-
任何面向字节的传输层都可以通过实现 `AbstractPhysicalLayer` 和 `AbstractPhysicalConnection` 来使用,然后传入 `{ type: 'CUSTOM', layer: yourLayer }`。
|
|
158
|
-
|
|
159
|
-
```typescript
|
|
160
|
-
import { AbstractPhysicalLayer, AbstractPhysicalConnection } from 'njs-modbus';
|
|
161
|
-
|
|
162
|
-
class MyPhysicalLayer extends AbstractPhysicalLayer { /* open / close */ }
|
|
163
|
-
class MyConnection extends AbstractPhysicalConnection { /* write / destroy, emit 'data' */ }
|
|
164
|
-
|
|
165
|
-
const master = new ModbusMaster({
|
|
166
|
-
physical: { type: 'CUSTOM', layer: new MyPhysicalLayer() },
|
|
167
|
-
protocol: { type: 'TCP' },
|
|
168
|
-
});
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
查看 [`examples/websocket`](./examples/websocket) 获取完整的 **WebSocket 承载 Modbus TCP** 实现——包含客户端/服务端物理层及可运行的演示。
|
|
185
|
+
## 协议层
|
|
172
186
|
|
|
173
|
-
|
|
187
|
+
| 协议 | 选项 | 说明 |
|
|
188
|
+
|------|------|------|
|
|
189
|
+
| `TCP` | 无 | Modbus TCP,带 MBAP 头 |
|
|
190
|
+
| `RTU` | `RtuProtocolOptions` | Modbus RTU,带 CRC16 |
|
|
191
|
+
| `ASCII` | `AsciiApplicationLayerOptions` | Modbus ASCII,带 LRC |
|
|
174
192
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
new ModbusMaster({
|
|
179
|
-
physical: { type: 'TCP_CLIENT' },
|
|
180
|
-
protocol: { type: 'TCP' }, // 'TCP' | 'RTU' | 'ASCII'
|
|
181
|
-
timeout?: 1000, // 单次请求超时(毫秒)
|
|
182
|
-
concurrent?: false, // 流水线模式(仅 TCP)
|
|
183
|
-
})
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
RTU 帧选项:
|
|
193
|
+
### RTU 选项
|
|
187
194
|
|
|
188
195
|
```typescript
|
|
189
196
|
protocol: {
|
|
190
197
|
type: 'RTU',
|
|
191
198
|
opts: {
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
199
|
+
// t3.5 帧间静默时间。
|
|
200
|
+
// 既可以传裸数字(毫秒),也可以传 { unit: 'bit' | 'ms', value: N }。
|
|
201
|
+
// 传 0 显式禁用(适用于 RTU-over-TCP 等无丢包传输)。
|
|
202
|
+
intervalBetweenFrames: 20,
|
|
203
|
+
|
|
204
|
+
// t1.5 字符间超时(可选)。
|
|
205
|
+
interCharTimeout: { unit: 'bit', value: 10 },
|
|
206
|
+
|
|
207
|
+
// 丢弃存在 t1.5 时序违规的帧。
|
|
208
|
+
strictTiming: true,
|
|
197
209
|
},
|
|
198
210
|
}
|
|
199
211
|
```
|
|
200
212
|
|
|
201
|
-
ASCII
|
|
213
|
+
### ASCII 选项
|
|
202
214
|
|
|
203
215
|
```typescript
|
|
204
216
|
protocol: {
|
|
@@ -209,11 +221,24 @@ protocol: {
|
|
|
209
221
|
}
|
|
210
222
|
```
|
|
211
223
|
|
|
224
|
+
## 主站 API
|
|
225
|
+
|
|
226
|
+
### 构造函数
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
new ModbusMaster({
|
|
230
|
+
physical: { type: 'TCP_CLIENT' },
|
|
231
|
+
protocol: { type: 'TCP' }, // 'TCP' | 'RTU' | 'ASCII'
|
|
232
|
+
timeout?: 1000, // 单次请求超时(毫秒)
|
|
233
|
+
concurrent?: false, // 流水线模式(仅 TCP)
|
|
234
|
+
})
|
|
235
|
+
```
|
|
236
|
+
|
|
212
237
|
### 方法
|
|
213
238
|
|
|
214
239
|
| 方法 | 说明 |
|
|
215
|
-
|
|
216
|
-
| `open(...args)` |
|
|
240
|
+
|------|------|
|
|
241
|
+
| `open(...args)` | 打开物理层。一次性:close() 后不可重新打开。 |
|
|
217
242
|
| `close()` | 立即关闭。进行中和队列中的请求会被 reject。 |
|
|
218
243
|
| `readCoils(unit, address, length, timeout?)` | FC 01 |
|
|
219
244
|
| `readDiscreteInputs(unit, address, length, timeout?)` | FC 02 |
|
|
@@ -235,6 +260,8 @@ protocol: {
|
|
|
235
260
|
|
|
236
261
|
## 从站 API
|
|
237
262
|
|
|
263
|
+
### 构造函数
|
|
264
|
+
|
|
238
265
|
```typescript
|
|
239
266
|
new ModbusSlave({
|
|
240
267
|
physical: { type: 'TCP_SERVER' },
|
|
@@ -252,10 +279,10 @@ slave.add({
|
|
|
252
279
|
// 可选:在默认分发前拦截任意功能码
|
|
253
280
|
interceptor?: (fc, data) => Buffer | undefined,
|
|
254
281
|
|
|
255
|
-
readCoils?: (address, length) =>
|
|
256
|
-
readDiscreteInputs?: (address, length) =>
|
|
257
|
-
readHoldingRegisters?: (address, length) => number[],
|
|
258
|
-
readInputRegisters?: (address, length) => number[],
|
|
282
|
+
readCoils?: (address, length) => Uint8Array,
|
|
283
|
+
readDiscreteInputs?: (address, length) => Uint8Array,
|
|
284
|
+
readHoldingRegisters?: (address, length) => number[] | Uint16Array,
|
|
285
|
+
readInputRegisters?: (address, length) => number[] | Uint16Array,
|
|
259
286
|
|
|
260
287
|
writeSingleCoil?: (address, value) => void,
|
|
261
288
|
writeMultipleCoils?: (address, values) => void,
|
|
@@ -280,29 +307,70 @@ slave.add({
|
|
|
280
307
|
|
|
281
308
|
缺失的处理器返回 `ILLEGAL_FUNCTION`。越界地址返回 `ILLEGAL_DATA_ADDRESS`。处理器抛出的异常变为 `SERVER_DEVICE_FAILURE`,除非错误是 `ModbusError`。
|
|
282
309
|
|
|
310
|
+
### 方法
|
|
311
|
+
|
|
283
312
|
| 方法 | 说明 |
|
|
284
|
-
|
|
313
|
+
|------|------|
|
|
285
314
|
| `add(model)` | 注册从站模型 |
|
|
286
|
-
| `remove(unit)` |
|
|
287
|
-
| `open(...args)` |
|
|
315
|
+
| `remove(unit)` | 移除模型 |
|
|
316
|
+
| `open(...args)` | 打开并开始接受连接。一次性。 |
|
|
288
317
|
| `close()` | 立即关闭 |
|
|
289
318
|
| `addCustomFunctionCode(cfc)` | 注册自定义功能码 |
|
|
290
319
|
| `removeCustomFunctionCode(fc)` | 注销自定义功能码 |
|
|
291
320
|
|
|
321
|
+
## 事件
|
|
322
|
+
|
|
323
|
+
`ModbusMaster` 和 `ModbusSlave` 都是 `EventEmitter`,所有事件均带类型定义。
|
|
324
|
+
|
|
325
|
+
### 物理层事件
|
|
326
|
+
|
|
327
|
+
| 事件 | 参数 | 说明 |
|
|
328
|
+
|------|------|------|
|
|
329
|
+
| `open` | `()` | 物理层就绪,可接受连接 |
|
|
330
|
+
| `connect` | `(connection)` | 新连接已建立 |
|
|
331
|
+
| `close` | `()` | 物理层已关闭 |
|
|
332
|
+
| `error` | `(error)` | 物理层错误 |
|
|
333
|
+
|
|
334
|
+
### 连接调试事件
|
|
335
|
+
|
|
336
|
+
| 事件 | 参数 | 说明 |
|
|
337
|
+
|------|------|------|
|
|
338
|
+
| `tx` | `(buffer, connection)` | 原始数据已写入链路 |
|
|
339
|
+
| `rx` | `(buffer, connection)` | 从链路接收到原始数据 |
|
|
340
|
+
|
|
341
|
+
### 应用层事件
|
|
342
|
+
|
|
343
|
+
| 事件 | 参数 | 说明 |
|
|
344
|
+
|------|------|------|
|
|
345
|
+
| `framing` | `(frame, connection)` | 完整帧已解码 |
|
|
346
|
+
| `framingError` | `(error, connection)` | 帧解析错误(CRC/LRC 失败、MBAP 格式错误、时序违规等) |
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
master.on('framing', (frame, connection) => {
|
|
350
|
+
console.log('frame:', frame.unit, frame.fc, frame.transaction);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
master.on('framingError', (error, connection) => {
|
|
354
|
+
console.log('framing error:', error.message);
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
292
358
|
## 自定义功能码
|
|
293
359
|
|
|
360
|
+
`predictRequestLength` / `predictResponseLength` 接收 `getByte` 访问器和当前可用字节数 `length`。请使用 `length` 做边界检查,不要直接访问缓冲区。
|
|
361
|
+
|
|
294
362
|
```typescript
|
|
295
363
|
import type { CustomFunctionCode } from 'njs-modbus';
|
|
296
364
|
|
|
297
365
|
const cfc: CustomFunctionCode = {
|
|
298
366
|
fc: 0x50,
|
|
299
|
-
predictRequestLength: (
|
|
300
|
-
if (
|
|
301
|
-
return 4 +
|
|
367
|
+
predictRequestLength: (getByte, length) => {
|
|
368
|
+
if (length < 2) return 0; // 需要更多字节
|
|
369
|
+
return 4 + getByte(1);
|
|
302
370
|
},
|
|
303
|
-
predictResponseLength: (
|
|
304
|
-
if (
|
|
305
|
-
return 4 +
|
|
371
|
+
predictResponseLength: (getByte, length) => {
|
|
372
|
+
if (length < 2) return 0;
|
|
373
|
+
return 4 + getByte(1);
|
|
306
374
|
},
|
|
307
375
|
handle: async (data, unit) => {
|
|
308
376
|
return Buffer.from([data[1], data[0]]);
|
|
@@ -343,57 +411,65 @@ slave.add({
|
|
|
343
411
|
});
|
|
344
412
|
```
|
|
345
413
|
|
|
346
|
-
##
|
|
347
|
-
|
|
348
|
-
与 [jsmodbus](https://github.com/Cloud-Automation/node-modbus) 和 [modbus-serial](https://github.com/yaacov/node-modbus-serial) 的对比。
|
|
349
|
-
|
|
350
|
-
| 指标 | njs-modbus | jsmodbus | modbus-serial |
|
|
351
|
-
|------|-----------|----------|---------------|
|
|
352
|
-
| TCP 吞吐量 | **5,527 ops/sec** | 3,239 (0.59x) | 371 (0.07x) |
|
|
353
|
-
| TCP P99 延迟 | **2.71 ms** | 4.73 ms (1.75x) | 12.48 ms (4.61x) |
|
|
354
|
-
| TCP CPU 效率 | **1,116 µs/op** | 1,950 (1.75x) | 16,715 (14.98x) |
|
|
355
|
-
| 并发 (8 连接) | **5,274 ops/sec** | 3,416 (0.65x) | 1,815 (0.34x) |
|
|
356
|
-
| RTU CPU 效率 | **1,762 µs/op** | 1,760 (1.00x) | 2,144 (1.22x) |
|
|
357
|
-
| TCP 响应编码 | **2.04M ops/sec** | 373K (0.18x) | 411K (0.20x) |
|
|
358
|
-
| TCP 响应解码 | **1.91M ops/sec** | 538K (0.28x) | 231K (0.12x) |
|
|
414
|
+
## 自定义物理层
|
|
359
415
|
|
|
360
|
-
|
|
361
|
-
<summary>完整基准测试结果</summary>
|
|
416
|
+
任何面向字节的传输层都可以通过实现 `AbstractPhysicalLayer` 和 `AbstractPhysicalConnection` 来使用,然后传入 `{ type: 'CUSTOM', layer: yourLayer }`。
|
|
362
417
|
|
|
363
|
-
|
|
418
|
+
```typescript
|
|
419
|
+
import { AbstractPhysicalLayer, AbstractPhysicalConnection } from 'njs-modbus';
|
|
364
420
|
|
|
365
|
-
|
|
421
|
+
class MyPhysicalLayer extends AbstractPhysicalLayer { /* open / close */ }
|
|
422
|
+
class MyConnection extends AbstractPhysicalConnection { /* write / destroy, emit 'data' */ }
|
|
366
423
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
424
|
+
const master = new ModbusMaster({
|
|
425
|
+
physical: { type: 'CUSTOM', layer: new MyPhysicalLayer() },
|
|
426
|
+
protocol: { type: 'TCP' },
|
|
427
|
+
});
|
|
371
428
|
```
|
|
372
429
|
|
|
373
|
-
|
|
430
|
+
查看 [`examples/websocket`](./examples/websocket) 获取完整的 **WebSocket 承载 Modbus TCP** 实现。
|
|
374
431
|
|
|
375
|
-
|
|
376
|
-
njs-modbus │ 5,274 ops/sec 🏆 CPU: 1,392 µs/op
|
|
377
|
-
jsmodbus │ 3,416 ops/sec (0.65x) CPU: 2,131 µs/op
|
|
378
|
-
modbus-serial │ 1,815 ops/sec (0.34x) CPU: 3,962 µs/op
|
|
379
|
-
```
|
|
432
|
+
查看 [`examples/bluetooth`](./examples/bluetooth) 获取基于 Nordic UART Service (NUS) 的 **BLE 承载 Modbus TCP** 实现。
|
|
380
433
|
|
|
381
|
-
|
|
434
|
+
## 性能
|
|
382
435
|
|
|
383
|
-
|
|
384
|
-
njs-modbus │ 44 ops/sec CPU: 1,762 µs/op
|
|
385
|
-
jsmodbus │ 44 ops/sec CPU: 1,760 µs/op
|
|
386
|
-
modbus-serial │ 44 ops/sec CPU: 2,144 µs/op
|
|
387
|
-
```
|
|
436
|
+
与 [jsmodbus](https://github.com/Cloud-Automation/node-modbus) v4.0.10 和 [modbus-serial](https://github.com/yaacov/node-modbus-serial) v8.0.25 的对比。
|
|
388
437
|
|
|
389
|
-
|
|
438
|
+
测试环境:AMD Ryzen 7 9800X3D 8-Core Processor · Node.js v24.16.0 · [完整报告](./benchmark/report_presentation.md)
|
|
390
439
|
|
|
391
|
-
|
|
392
|
-
tcpResEncode: njs-modbus 2.04M ops/sec (jsmodbus 0.18x, modbus-serial 0.20x)
|
|
393
|
-
tcpResDecode: njs-modbus 1.91M ops/sec (jsmodbus 0.28x, modbus-serial 0.12x)
|
|
394
|
-
```
|
|
440
|
+
### TCP 端到端
|
|
395
441
|
|
|
396
|
-
|
|
442
|
+
| 指标 | njs-modbus | jsmodbus | modbus-serial |
|
|
443
|
+
|------|-----------|----------|---------------|
|
|
444
|
+
| 单连接 | **74,964 ops/sec** 🏆 | 55,996 (0.75x) | 853 (0.01x) |
|
|
445
|
+
| 8 并发客户端 | **10,188 ops/sec** 🏆 | 5,918 (0.58x) | 728 (0.07x) |
|
|
446
|
+
| P99 延迟(单连接) | **17 µs** 🏆 | 15 µs (0.88x) | 1,206 µs (70.9x) |
|
|
447
|
+
|
|
448
|
+
### 帧编码 / 解码(CPU 微基准)
|
|
449
|
+
|
|
450
|
+
| 基准测试 | njs-modbus | jsmodbus | modbus-serial |
|
|
451
|
+
|----------|-----------|----------|---------------|
|
|
452
|
+
| TCP 请求编码 | **9.61M ops/sec** 🏆 | 6.32M (0.66x) | 0.68M (0.07x) |
|
|
453
|
+
| TCP 响应编码 | **7.51M ops/sec** 🏆 | 1.18M (0.16x) | 0.44M (0.06x) |
|
|
454
|
+
| TCP 响应解码 | **8.55M ops/sec** 🏆 | 2.04M (0.24x) | 0.70M (0.08x) |
|
|
455
|
+
| RTU 请求编码 | **9.42M ops/sec** 🏆 | 3.03M (0.32x) | 6.57M (0.70x) |
|
|
456
|
+
| ASCII 请求编码 | **7.09M ops/sec** 🏆 | — | 4.11M (0.58x) |
|
|
457
|
+
| ASCII 请求解码 | **4.91M ops/sec** 🏆 | — | 1.19M (0.24x) |
|
|
458
|
+
|
|
459
|
+
### 全功能码 TCP 吞吐(100 线圈 / 50 寄存器负载)
|
|
460
|
+
|
|
461
|
+
| 功能码 | njs-modbus | jsmodbus | modbus-serial |
|
|
462
|
+
|--------|-----------|----------|---------------|
|
|
463
|
+
| FC01 读取线圈 | **75,430** 🏆 | 488 (0.01x) | 859 (0.01x) |
|
|
464
|
+
| FC03 读取保持寄存器 | **82,028** 🏆 | 46,596 (0.57x) | 864 (0.01x) |
|
|
465
|
+
| FC06 写单个寄存器 | **86,110** 🏆 | 51,084 (0.59x) | 871 (0.01x) |
|
|
466
|
+
| FC15 写多个线圈 | **78,766** 🏆 | — | 867 (0.01x) |
|
|
467
|
+
| FC17 报告服务器 ID | **79,185** 🏆 | — | — |
|
|
468
|
+
| FC22 掩码写寄存器 | **73,060** 🏆 | — | — |
|
|
469
|
+
| FC23 读/写多个寄存器 | **68,429** 🏆 | — | — |
|
|
470
|
+
| FC43 读取设备标识 | **62,176** 🏆 | — | 868 (0.01x) |
|
|
471
|
+
|
|
472
|
+
> FC17 / FC22 / FC23 / FC43 不受 jsmodbus 支持。
|
|
397
473
|
|
|
398
474
|
## 许可证
|
|
399
475
|
|