You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Modbus Server与Client寄存器读写不一致问题求助

Modbus Server/Client 通信异常问题解决

问题现象

在Ubuntu虚拟机中模拟Modbus通信时,出现以下异常:

  • Server持续向寄存器0写入随机值,但Client首次读取时只能得到初始值0,无法获取Server写入的随机值。
  • Client向寄存器0写入值后,后续运行只能读取到自身写入的值,无法获取Server持续更新的新值。

原代码及输出

Server代码

import random
from pyModbusTCP.server import ModbusServer, DataBank
from time import sleep

#instance of ModbusServer
server = ModbusServer("127.0.0.1", 12344, no_block=True)

#instance of DataBank
data_bank = DataBank()
server.data_bank = data_bank

try:
    print("Start Server...")
    server.start()
    print("Server is online")
    state = 0
    while True:
        data_bank.set_holding_registers(0, [random.randint(1, 100)])  # Set holding register values
        if state != data_bank.get_holding_registers(0, 1)[0]:  # Get holding register values
            state = data_bank.get_holding_registers(0, 1)[0]
            print("Value of Register 1 has changed to " + str(state))
            sleep(1)
except Exception as e:
    print(f"An error occurred: {e}")
    print("Shutdown server...")
    server.stop()
    print("Server is stopped")

Server输出

Start Server...
Server is online
Value of Register 1 has changed to 88
Value of Register 1 has changed to 83
Value of Register 1 has changed to 51
Value of Register 1 has changed to 61
Value of Register 1 has changed to 45
^CTraceback (most recent call last):
  File "/home/neptun/Desktop/modbusyt/server.py", line 22, in <module>
    sleep(1)
KeyboardInterrupt

Client代码

import pyModbusTCP
from pyModbusTCP.client import ModbusClient

client = ModbusClient(host='127.0.0.1', port=12344, auto_open=True, debug=False)

try:
    regs = client.read_holding_registers(0, 1)
    if regs:
        print(regs)
    else:
        print("Read error")
except pyModbusTCP.ModbusIOException as e:
    print(f"Error reading registers: {e}")

try:
    client.write_multiple_registers(0, [1, 2, 3])
    regs = client.read_holding_registers(0, 5)
    if regs:
        print(regs)
    else:
        print("Read error")
except pyModbusTCP.ModbusIOException as e:
   print(f"Error writing registers: {e}")

Client输出

# first run:
[0]
[1, 2, 3, 0, 0]
# Consecutive runs:
[1]
[1, 2, 3, 0, 0]

问题根源

  1. Server CPU占用过高:原Server代码中仅在寄存器值变化时执行sleep(1),若随机值重复会导致无限循环,占用100%CPU,使得Modbus服务线程无法及时处理客户端请求。
  2. 读取时机不合理:Client首次读取时,可能在Server完成第一次寄存器写入前就发起请求,导致读到初始值0。
  3. 线程同步隐患:自定义DataBank实例后,主线程与服务线程的寄存器操作可能存在同步问题。

修复方案

修改后的Server代码

import random
from pyModbusTCP.server import ModbusServer
from time import sleep

# 初始化Modbus服务器
server = ModbusServer("127.0.0.1", 12344, no_block=True)

try:
    print("启动服务器...")
    server.start()
    print("服务器已上线")
    state = 0
    while True:
        # 生成随机值并写入寄存器0
        new_val = random.randint(1, 100)
        server.data_bank.set_holding_registers(0, [new_val])
        # 仅当值变化时打印日志
        if state != new_val:
            state = new_val
            print(f"寄存器0的值已变更为 {state}")
        # 固定每秒更新一次,避免CPU占用过高
        sleep(1)
except Exception as e:
    print(f"发生错误: {e}")
    print("正在关闭服务器...")
    server.stop()
    print("服务器已停止")

修改后的Client代码

from pyModbusTCP.client import ModbusClient
from time import sleep

# 初始化客户端,手动控制连接
client = ModbusClient(host='127.0.0.1', port=12344, auto_open=False, debug=False)

# 尝试连接服务器
if not client.open():
    print("无法连接到Modbus服务器")
    exit()

try:
    # 等待服务器完成初始写入,确保读取到有效数据
    sleep(0.5)
    # 读取寄存器0的值
    regs = client.read_holding_registers(0, 1)
    if regs:
        print(f"读取寄存器0的值: {regs}")
    else:
        print("读取寄存器0失败")
except Exception as e:
    print(f"读取错误: {e}")

try:
    # 向寄存器0、1、2写入值1、2、3
    if client.write_multiple_registers(0, [1, 2, 3]):
        print("写入寄存器成功")
        # 读取寄存器0-4的值
        regs = client.read_holding_registers(0, 5)
        if regs:
            print(f"读取寄存器0-4的值: {regs}")
        else:
            print("读取寄存器0-4失败")
    else:
        print("写入寄存器失败")
except Exception as e:
    print(f"写入错误: {e}")

# 关闭客户端连接
client.close()

修复说明

  1. Server端:

    • 将sleep(1)移到循环末尾,固定每秒更新一次寄存器,彻底解决CPU占用过高问题,保证服务线程正常响应客户端请求。
    • 直接使用服务器自带的data_bank,避免自定义实例的关联隐患。
    • 提前生成随机值,减少重复读取寄存器的开销。
  2. Client端:

    • 手动控制连接流程,增加连接失败的判断逻辑。
    • 增加短暂延迟,确保服务器完成初始写入后再读取,避免首次读到初始值0。
    • 增加写入操作的结果判断,便于排查问题。

内容的提问来源于stack exchange,提问作者Shivansh Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 05:05:23