njs-modbus 3.3.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 +177 -131
- package/README.zh-CN.md +177 -130
- package/dist/index.cjs +715 -519
- package/dist/index.d.ts +86 -61
- package/dist/index.mjs +715 -519
- package/dist/utils.cjs +53 -25
- package/dist/utils.d.ts +15 -14
- package/dist/utils.mjs +49 -24
- package/package.json +3 -9
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 | 读取线圈 |
|
|
@@ -116,20 +119,45 @@ const master = new ModbusMaster({
|
|
|
116
119
|
});
|
|
117
120
|
```
|
|
118
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
|
+
|
|
119
147
|
## 物理层
|
|
120
148
|
|
|
121
|
-
所有物理层暴露 `open()` / `close()`、`state`
|
|
149
|
+
所有物理层暴露 `open()` / `close()`、`state` 属性,以及 [事件](#事件) 章节中列出的事件。
|
|
122
150
|
|
|
123
|
-
| 类型 |
|
|
124
|
-
|
|
125
|
-
| `SERIAL` | `
|
|
126
|
-
| `TCP_CLIENT` | `
|
|
127
|
-
| `TCP_SERVER` | `
|
|
128
|
-
| `UDP_CLIENT` | `
|
|
129
|
-
| `UDP_SERVER` | `
|
|
130
|
-
| `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` 实例 |
|
|
131
159
|
|
|
132
|
-
### 服务端配置
|
|
160
|
+
### TCP 服务端配置
|
|
133
161
|
|
|
134
162
|
```typescript
|
|
135
163
|
const slave = new ModbusSlave({
|
|
@@ -145,62 +173,44 @@ const slave = new ModbusSlave({
|
|
|
145
173
|
});
|
|
146
174
|
```
|
|
147
175
|
|
|
148
|
-
###
|
|
176
|
+
### 物理层选项参考
|
|
149
177
|
|
|
150
178
|
| 选项 | 类型 | 说明 |
|
|
151
|
-
|
|
179
|
+
|------|------|------|
|
|
152
180
|
| `whitelist` | `string[]` | 允许的客户端 IP。`::ffff:` 前缀自动剥离。 |
|
|
153
181
|
| `maxConnections` | `number` | 最大并发连接数。超出后新连接静默丢弃。 |
|
|
154
182
|
| `idleTimeout` | `number` | 空闲超时(毫秒),超时后驱逐连接。默认 `30000`,传 `0` 禁用。 |
|
|
155
183
|
| `socketOpts` / `serverOpts` | `object` | 透传给 Node.js `createSocket()` / `createServer()`。 |
|
|
156
184
|
|
|
157
|
-
##
|
|
158
|
-
|
|
159
|
-
任何面向字节的传输层都可以通过实现 `AbstractPhysicalLayer` 和 `AbstractPhysicalConnection` 来使用,然后传入 `{ type: 'CUSTOM', layer: yourLayer }`。
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
import { AbstractPhysicalLayer, AbstractPhysicalConnection } from 'njs-modbus';
|
|
163
|
-
|
|
164
|
-
class MyPhysicalLayer extends AbstractPhysicalLayer { /* open / close */ }
|
|
165
|
-
class MyConnection extends AbstractPhysicalConnection { /* write / destroy, emit 'data' */ }
|
|
166
|
-
|
|
167
|
-
const master = new ModbusMaster({
|
|
168
|
-
physical: { type: 'CUSTOM', layer: new MyPhysicalLayer() },
|
|
169
|
-
protocol: { type: 'TCP' },
|
|
170
|
-
});
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
查看 [`examples/websocket`](./examples/websocket) 获取完整的 **WebSocket 承载 Modbus TCP** 实现——包含客户端/服务端物理层及可运行的演示。
|
|
185
|
+
## 协议层
|
|
174
186
|
|
|
175
|
-
|
|
187
|
+
| 协议 | 选项 | 说明 |
|
|
188
|
+
|------|------|------|
|
|
189
|
+
| `TCP` | 无 | Modbus TCP,带 MBAP 头 |
|
|
190
|
+
| `RTU` | `RtuProtocolOptions` | Modbus RTU,带 CRC16 |
|
|
191
|
+
| `ASCII` | `AsciiApplicationLayerOptions` | Modbus ASCII,带 LRC |
|
|
176
192
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
new ModbusMaster({
|
|
181
|
-
physical: { type: 'TCP_CLIENT' },
|
|
182
|
-
protocol: { type: 'TCP' }, // 'TCP' | 'RTU' | 'ASCII'
|
|
183
|
-
timeout?: 1000, // 单次请求超时(毫秒)
|
|
184
|
-
concurrent?: false, // 流水线模式(协议:仅 TCP)
|
|
185
|
-
})
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
RTU 帧选项:
|
|
193
|
+
### RTU 选项
|
|
189
194
|
|
|
190
195
|
```typescript
|
|
191
196
|
protocol: {
|
|
192
197
|
type: 'RTU',
|
|
193
198
|
opts: {
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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,
|
|
199
209
|
},
|
|
200
210
|
}
|
|
201
211
|
```
|
|
202
212
|
|
|
203
|
-
ASCII
|
|
213
|
+
### ASCII 选项
|
|
204
214
|
|
|
205
215
|
```typescript
|
|
206
216
|
protocol: {
|
|
@@ -211,11 +221,24 @@ protocol: {
|
|
|
211
221
|
}
|
|
212
222
|
```
|
|
213
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
|
+
|
|
214
237
|
### 方法
|
|
215
238
|
|
|
216
239
|
| 方法 | 说明 |
|
|
217
|
-
|
|
218
|
-
| `open(...args)` |
|
|
240
|
+
|------|------|
|
|
241
|
+
| `open(...args)` | 打开物理层。一次性:close() 后不可重新打开。 |
|
|
219
242
|
| `close()` | 立即关闭。进行中和队列中的请求会被 reject。 |
|
|
220
243
|
| `readCoils(unit, address, length, timeout?)` | FC 01 |
|
|
221
244
|
| `readDiscreteInputs(unit, address, length, timeout?)` | FC 02 |
|
|
@@ -237,11 +260,13 @@ protocol: {
|
|
|
237
260
|
|
|
238
261
|
## 从站 API
|
|
239
262
|
|
|
263
|
+
### 构造函数
|
|
264
|
+
|
|
240
265
|
```typescript
|
|
241
266
|
new ModbusSlave({
|
|
242
267
|
physical: { type: 'TCP_SERVER' },
|
|
243
268
|
protocol: { type: 'TCP' },
|
|
244
|
-
concurrent?: false, //
|
|
269
|
+
concurrent?: false, // 每连接并发(仅 TCP)
|
|
245
270
|
})
|
|
246
271
|
```
|
|
247
272
|
|
|
@@ -254,8 +279,8 @@ slave.add({
|
|
|
254
279
|
// 可选:在默认分发前拦截任意功能码
|
|
255
280
|
interceptor?: (fc, data) => Buffer | undefined,
|
|
256
281
|
|
|
257
|
-
readCoils?: (address, length) =>
|
|
258
|
-
readDiscreteInputs?: (address, length) =>
|
|
282
|
+
readCoils?: (address, length) => Uint8Array,
|
|
283
|
+
readDiscreteInputs?: (address, length) => Uint8Array,
|
|
259
284
|
readHoldingRegisters?: (address, length) => number[] | Uint16Array,
|
|
260
285
|
readInputRegisters?: (address, length) => number[] | Uint16Array,
|
|
261
286
|
|
|
@@ -282,31 +307,70 @@ slave.add({
|
|
|
282
307
|
|
|
283
308
|
缺失的处理器返回 `ILLEGAL_FUNCTION`。越界地址返回 `ILLEGAL_DATA_ADDRESS`。处理器抛出的异常变为 `SERVER_DEVICE_FAILURE`,除非错误是 `ModbusError`。
|
|
284
309
|
|
|
310
|
+
### 方法
|
|
311
|
+
|
|
285
312
|
| 方法 | 说明 |
|
|
286
|
-
|
|
313
|
+
|------|------|
|
|
287
314
|
| `add(model)` | 注册从站模型 |
|
|
288
|
-
| `remove(unit)` |
|
|
289
|
-
| `open(...args)` |
|
|
315
|
+
| `remove(unit)` | 移除模型 |
|
|
316
|
+
| `open(...args)` | 打开并开始接受连接。一次性。 |
|
|
290
317
|
| `close()` | 立即关闭 |
|
|
291
318
|
| `addCustomFunctionCode(cfc)` | 注册自定义功能码 |
|
|
292
319
|
| `removeCustomFunctionCode(fc)` | 注销自定义功能码 |
|
|
293
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
|
+
|
|
294
358
|
## 自定义功能码
|
|
295
359
|
|
|
296
|
-
`predictRequestLength` / `predictResponseLength`
|
|
360
|
+
`predictRequestLength` / `predictResponseLength` 接收 `getByte` 访问器和当前可用字节数 `length`。请使用 `length` 做边界检查,不要直接访问缓冲区。
|
|
297
361
|
|
|
298
362
|
```typescript
|
|
299
363
|
import type { CustomFunctionCode } from 'njs-modbus';
|
|
300
364
|
|
|
301
365
|
const cfc: CustomFunctionCode = {
|
|
302
366
|
fc: 0x50,
|
|
303
|
-
predictRequestLength: (
|
|
304
|
-
if (
|
|
305
|
-
return 4 +
|
|
367
|
+
predictRequestLength: (getByte, length) => {
|
|
368
|
+
if (length < 2) return 0; // 需要更多字节
|
|
369
|
+
return 4 + getByte(1);
|
|
306
370
|
},
|
|
307
|
-
predictResponseLength: (
|
|
308
|
-
if (
|
|
309
|
-
return 4 +
|
|
371
|
+
predictResponseLength: (getByte, length) => {
|
|
372
|
+
if (length < 2) return 0;
|
|
373
|
+
return 4 + getByte(1);
|
|
310
374
|
},
|
|
311
375
|
handle: async (data, unit) => {
|
|
312
376
|
return Buffer.from([data[1], data[0]]);
|
|
@@ -347,82 +411,65 @@ slave.add({
|
|
|
347
411
|
});
|
|
348
412
|
```
|
|
349
413
|
|
|
350
|
-
##
|
|
414
|
+
## 自定义物理层
|
|
415
|
+
|
|
416
|
+
任何面向字节的传输层都可以通过实现 `AbstractPhysicalLayer` 和 `AbstractPhysicalConnection` 来使用,然后传入 `{ type: 'CUSTOM', layer: yourLayer }`。
|
|
351
417
|
|
|
352
|
-
|
|
418
|
+
```typescript
|
|
419
|
+
import { AbstractPhysicalLayer, AbstractPhysicalConnection } from 'njs-modbus';
|
|
353
420
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
| TCP 吞吐量 | **70,544 ops/sec** | 39,827 (0.56x) | 786 (0.01x) |
|
|
357
|
-
| TCP P99 延迟 | **53 µs** | 98 µs (1.83x) | 2,331 µs (43.7x) |
|
|
358
|
-
| 并发 (8 连接) | **75,810 ops/sec** | 41,754 (0.55x) | 5,620 (0.07x) |
|
|
359
|
-
| RTU 串口 (115200 波特率) | **44 ops/sec** | 44 ops/sec | 45 ops/sec |
|
|
360
|
-
| TCP 响应编码 | **6.57M ops/sec** | 1.22M (0.19x) | 1.18M (0.18x) |
|
|
361
|
-
| TCP 响应解码 | **6.78M ops/sec** | 1.94M (0.29x) | 0.67M (0.10x) |
|
|
362
|
-
| FC01 读取线圈 | **85,170 ops/sec** | 617 (0.01x) | 861 (0.01x) |
|
|
421
|
+
class MyPhysicalLayer extends AbstractPhysicalLayer { /* open / close */ }
|
|
422
|
+
class MyConnection extends AbstractPhysicalConnection { /* write / destroy, emit 'data' */ }
|
|
363
423
|
|
|
364
|
-
|
|
365
|
-
|
|
424
|
+
const master = new ModbusMaster({
|
|
425
|
+
physical: { type: 'CUSTOM', layer: new MyPhysicalLayer() },
|
|
426
|
+
protocol: { type: 'TCP' },
|
|
427
|
+
});
|
|
428
|
+
```
|
|
366
429
|
|
|
367
|
-
|
|
430
|
+
查看 [`examples/websocket`](./examples/websocket) 获取完整的 **WebSocket 承载 Modbus TCP** 实现。
|
|
368
431
|
|
|
369
|
-
|
|
432
|
+
查看 [`examples/bluetooth`](./examples/bluetooth) 获取基于 Nordic UART Service (NUS) 的 **BLE 承载 Modbus TCP** 实现。
|
|
370
433
|
|
|
371
|
-
|
|
372
|
-
njs-modbus │ ██████████████████████████████ 70,544 ops/sec 🏆 p99: 53 µs CPU: 91 µs/op
|
|
373
|
-
jsmodbus │ █████████████████░░░░░░░░░░░░░ 39,827 ops/sec (0.56x) p99: 98 µs CPU: 161 µs/op
|
|
374
|
-
modbus-serial │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 786 ops/sec (0.01x) p99: 2,331 µs CPU: 8,176 µs/op
|
|
375
|
-
```
|
|
434
|
+
## 性能
|
|
376
435
|
|
|
377
|
-
|
|
436
|
+
与 [jsmodbus](https://github.com/Cloud-Automation/node-modbus) v4.0.10 和 [modbus-serial](https://github.com/yaacov/node-modbus-serial) v8.0.25 的对比。
|
|
378
437
|
|
|
379
|
-
|
|
380
|
-
njs-modbus │ ██████████████████████████████ 75,810 ops/sec 🏆 p99: 258 µs CPU: 91 µs/op
|
|
381
|
-
jsmodbus │ █████████████████░░░░░░░░░░░░░ 41,754 ops/sec (0.55x) p99: 543 µs CPU: 167 µs/op
|
|
382
|
-
modbus-serial │ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 5,620 ops/sec (0.07x) p99: 3,180 µs CPU: 1,237 µs/op
|
|
383
|
-
```
|
|
438
|
+
测试环境:AMD Ryzen 7 9800X3D 8-Core Processor · Node.js v24.16.0 · [完整报告](./benchmark/report_presentation.md)
|
|
384
439
|
|
|
385
|
-
###
|
|
440
|
+
### TCP 端到端
|
|
386
441
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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) |
|
|
392
447
|
|
|
393
|
-
### 帧编码 / 解码(CPU
|
|
448
|
+
### 帧编码 / 解码(CPU 微基准)
|
|
394
449
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
asciiReqDecode: njs-modbus 3.37M ops/sec 🏆 modbus-serial 0.34x
|
|
404
|
-
```
|
|
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) |
|
|
405
458
|
|
|
406
|
-
### 全功能码 TCP
|
|
459
|
+
### 全功能码 TCP 吞吐(100 线圈 / 50 寄存器负载)
|
|
407
460
|
|
|
408
461
|
| 功能码 | njs-modbus | jsmodbus | modbus-serial |
|
|
409
462
|
|--------|-----------|----------|---------------|
|
|
410
|
-
| FC01 读取线圈 | **
|
|
411
|
-
|
|
|
412
|
-
|
|
|
413
|
-
|
|
|
414
|
-
|
|
|
415
|
-
|
|
|
416
|
-
|
|
|
417
|
-
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
| FC23 读/写多个寄存器 | **85,652** 🏆 | — | — |
|
|
421
|
-
| FC43 读取设备标识 | **78,030** 🏆 | — | 865 (0.01x) |
|
|
422
|
-
|
|
423
|
-
> FC17 / FC22 / FC23 不受 jsmodbus 和 modbus-serial 支持。
|
|
424
|
-
|
|
425
|
-
</details>
|
|
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 支持。
|
|
426
473
|
|
|
427
474
|
## 许可证
|
|
428
475
|
|