3. Modbus TCP客户端通信
任务目标
在网关设备上实现一个Modbus TCP客户端,能够主动连接远程Modbus TCP服务器,完成保持寄存器(Holding Register)的读取与写入操作,验证网关与远程服务器之间的数据交换链路。
环境与依赖
- 操作系统:Linux(网关标准环境,如Buildroot/Yocto)
- Python版本:3.6+
- 依赖库:
pymodbus(安装命令:pip install pymodbus) - 网络:网关与远程服务器之间TCP 502端口可达
实现方案
使用Python的pymodbus库实现客户端。核心逻辑包含三个部分:建立TCP连接、读取保持寄存器、写入保持寄存器。代码采用同步客户端模式,便于在网关启动脚本或定时任务中直接调用。服务器地址与端口通过命令行参数传入,便于部署时灵活配置。
关键完整代码
#!/usr/bin/env python3
"""Modbus TCP客户端 - 读取/写入保持寄存器"""
import argparse
import logging
from pymodbus.client import ModbusTcpClient
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger("modbus_client")
def read_holding_registers(client, address, count):
"""读取保持寄存器"""
result = client.read_holding_registers(address, count, slave=1)
if result.isError():
raise RuntimeError(f"读取失败: {result}")
return result.registers
def write_holding_register(client, address, value):
"""写入单个保持寄存器"""
result = client.write_register(address, value, slave=1)
if result.isError():
raise RuntimeError(f"写入失败: {result}")
log.info("写入成功: 地址=%d, 值=%d", address, value)
def main():
parser = argparse.ArgumentParser(description="Modbus TCP客户端")
parser.add_argument("--host", required=True, help="Modbus服务器IP")
parser.add_argument("--port", type=int, default=502, help="Modbus端口")
parser.add_argument("--read-addr", type=int, default=0, help="读取起始地址")
parser.add_argument("--read-count", type=int, default=2, help="读取寄存器数量")
parser.add_argument("--write-addr", type=int, help="写入地址")
parser.add_argument("--write-value", type=int, help="写入值")
args = parser.parse_args()
client = ModbusTcpClient(args.host, port=args.port, timeout=5)
if not client.connect():
log.error("无法连接服务器 %s:%d", args.host, args.port)
return 1
try:
# 执行写入操作(如果指定了写入参数)
if args.write_addr is not None and args.write_value is not None:
write_holding_register(client, args.write_addr, args.write_value)
# 执行读取操作
registers = read_holding_registers(client, args.read_addr, args.read_count)
log.info("读取寄存器[%d-%d]: %s", args.read_addr, args.read_addr + args.read_count - 1, registers)
print(f"READ_RESULT: {registers}")
except Exception as e:
log.error("操作异常: %s", e)
return 1
finally:
client.close()
return 0
if __name__ == "__main__":
exit(main())
运行方式
# 1. 安装依赖
pip install pymodbus
# 2. 读取操作(读取服务器地址0x00开始的2个寄存器)
python3 modbus_client.py --host 192.168.1.100 --read-addr 0 --read-count 2
# 3. 写入操作(向地址0x10写入值1234)
python3 modbus_client.py --host 192.168.1.100 --write-addr 16 --write-value 1234
# 4. 组合操作(先写入再读取验证)
python3 modbus_client.py --host 192.168.1.100 --write-addr 16 --write-value 1234 --read-addr 16 --read-count 1
验证方法
- 连通性验证:若服务器不可达,程序输出
无法连接服务器并返回退出码1;连接成功则继续执行后续操作。 - 读取验证:正常执行时输出
READ_RESULT: [值1, 值2, ...],寄存器数量与--read-count一致。 - 写入验证:日志显示
写入成功: 地址=16, 值=1234。若服务器端有监控工具(如Modbus Poll),可观察到寄存器值已更新。 - 闭环验证:使用组合操作命令,先写入已知值再读回,若输出值与写入值一致,则证明数据交换链路完整可用。
常见问题
- 连接超时:确认服务器IP/端口正确,且网关到服务器的TCP 502端口未被防火墙拦截。
- 从站地址不匹配:代码中固定使用
slave=1,若服务器配置的从站地址不同,需修改代码中的slave参数。 - 寄存器地址越界:读取或写入地址超出服务器映射范围时,pymodbus会返回异常错误,程序将打印错误信息并退出。