Pymodbus TCP服务器读写问题:远程修改变量后如何在服务端获取处理?
嘿,我刚好之前折腾过Pymodbus的TCP服务器变量监听问题,给你两个实用的解决方案,应该能帮到你:
方案1:用回调函数实时捕获修改(最推荐)
Pymodbus的服务器支持注册回调函数,当远程客户端修改寄存器时会自动触发,这样你就能第一时间拿到修改后的值并处理。举个具体的代码例子:
首先定义一个处理写入请求的回调函数:
def handle_register_write(request, response): # 提取客户端修改的寄存器地址和新值 start_address = request.address new_values = request.values print(f"收到远程修改:地址{start_address}开始的寄存器,新值为{new_values}") # 这里加入你的业务处理逻辑,比如更新本地监控变量、触发告警等 update_monitored_vars(start_address, new_values) # 记得返回响应,告知客户端修改成功 return response
然后在创建服务器时注册这个回调:
from pymodbus.server import StartTcpServer from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext # 初始化保持寄存器存储(这里创建100个初始值为10的可写寄存器) slave_store = ModbusSlaveContext(hr=[10]*100, di=None, co=None, ir=None) server_context = ModbusServerContext(slaves=slave_store, single=True) # 启动服务器并注册回调,监听保持寄存器的写入操作 server = StartTcpServer(context=server_context, address=("0.0.0.0", 502)) server.server.register_callback("write_registers", handle_register_write) server.serve_forever()
方案2:定时轮询存储(适合简单场景)
如果回调的方式对你的场景有点复杂,也可以通过定时读取服务器的寄存器存储,对比历史值来检测变化:
import time import threading from pymodbus.server import StartTcpServer from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext # 初始化寄存器存储和服务器上下文 slave_store = ModbusSlaveContext(hr=[10]*100) server_context = ModbusServerContext(slaves=slave_store, single=True) # 保存上一次的寄存器状态(3代表保持寄存器的功能码) last_register_values = slave_store.getValues(3, 0, count=100) def check_for_changes(): global last_register_values while True: current_values = slave_store.getValues(3, 0, count=100) if current_values != last_register_values: # 找出所有变化的寄存器位置和值 changed_positions = [i for i, (old, new) in enumerate(zip(last_register_values, current_values)) if old != new] for pos in changed_positions: print(f"寄存器{pos}的值从{last_register_values[pos]}变为{current_values[pos]}") # 执行你的处理逻辑 process_var_change(pos, current_values[pos]) last_register_values = current_values.copy() time.sleep(1) # 每秒轮询一次,可根据需求调整频率 # 启动轮询线程(设为守护线程,随服务器退出而终止) poll_thread = threading.Thread(target=check_for_changes) poll_thread.daemon = True poll_thread.start() # 启动TCP服务器 StartTcpServer(context=server_context, address=("0.0.0.0", 502))
几个注意点
- 如果你用的是异步服务器(比如
StartAsyncTcpServer),回调的注册方式会略有不同,需要适配异步逻辑。 - 确保你的寄存器存储是可写的,初始化时不要使用只读数据块。
- 处理共享变量时要注意线程安全,比如用
threading.Lock()来保护临界区代码。
内容的提问来源于stack exchange,提问作者MM87
相关产品推荐
相关产品推荐

