3. Modbus TCP服务器模拟

任务目标

实现一个基于Node.js的Modbus TCP服务器,模拟从站设备(Slave),能够响应标准Modbus TCP功能码请求(读保持寄存器0x03、写单个寄存器0x06、写多个寄存器0x10),用于在无真实硬件时测试Modbus主站(客户端)程序。

环境依赖

需要Node.js 14+环境,安装modbus-serial库(同时作为服务器和后续测试客户端)。

npm install modbus-serial

关键完整代码

以下代码创建了一个Modbus TCP服务器,监听端口8502,内部维护一个长度为10的保持寄存器数组(地址0~9),并实现读写请求的响应逻辑。

// modbus-tcp-server.js
const ModbusRTU = require("modbus-serial");

// 模拟从站数据区:保持寄存器(地址0~9)
const holdingRegisters = new Array(10).fill(0);
holdingRegisters[0] = 100;   // 设备状态
holdingRegisters[1] = 200;   // 运行参数

// 创建TCP服务器,绑定端口8502
const server = new ModbusRTU.ServerTCP({
    port: 8502,
    debug: false,
    unitID: 1,               // 从站单元标识符
    holdingRegister: holdingRegisters
});

// 监听服务器启动事件
server.on("initialized", () => {
    console.log("Modbus TCP 服务器已启动: 端口 8502, 单元ID=1");
    console.log("保持寄存器初始值:", holdingRegisters);
});

// 监听错误事件
server.on("error", (err) => {
    console.error("服务器错误:", err.message);
});

// 可选:监听请求日志(便于调试)
server.on("debug", (msg) => {
    console.log("请求日志:", msg);
});

运行与验证方法

启动服务器:

node modbus-tcp-server.js

看到控制台输出“服务器已启动”即表示监听成功。

验证读写功能(使用同一库作为客户端测试):

新建文件test-client.js,内容如下:

// test-client.js
const ModbusRTU = require("modbus-serial");

async function test() {
    const client = new ModbusRTU();
    await client.connectTCP("127.0.0.1", { port: 8502 });
    client.setID(1);

    // 1. 读保持寄存器(功能码0x03):读取地址0~2,共3个寄存器
    const readRes = await client.readHoldingRegisters(0, 3);
    console.log("读取结果:", readRes.data);  // 预期输出: [ 100, 200, 0 ]

    // 2. 写单个寄存器(功能码0x06):将地址2的值写为 300
    await client.writeRegister(2, 300);
    const readAfterSingle = await client.readHoldingRegisters(2, 1);
    console.log("写单个后读取:", readAfterSingle.data);  // 预期输出: [ 300 ]

    // 3. 写多个寄存器(功能码0x10):从地址3开始写入 [1, 2, 3]
    await client.writeRegisters(3, [1, 2, 3]);
    const readAfterMulti = await client.readHoldingRegisters(3, 3);
    console.log("写多个后读取:", readAfterMulti.data);  // 预期输出: [ 1, 2, 3 ]

    client.close();
    console.log("测试完成");
}

test().catch(console.error);

运行测试客户端:

node test-client.js

通过条件:客户端控制台依次输出以下三行结果,即表示服务器正确响应了三种读写请求:

读取结果: [ 100, 200, 0 ]
写单个后读取: [ 300 ]
写多个后读取: [ 1, 2, 3 ]

常见问题

  • 端口被占用:若8502被占用,修改代码中port值并同步修改客户端连接端口。
  • 连接失败:确认服务器已启动且客户端连接IP/端口一致;若跨设备测试,需将IP改为服务器实际IP并确保防火墙放行。
  • 寄存器地址越界:当前仅支持地址0~9,读写超出范围会返回异常码0x02(非法数据地址),属正常Modbus协议行为。