由于某些时候需要大量模拟Modbus设备对边缘网关进行压力测试,
使用Modbus模拟工具太麻烦且寄存器值无法自动递增,于是我们可以使用python来解决此问题。
以下代码可直接复制使用。
from pymodbus.server.sync import StartTcpServer, ModbusTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusSocketFramer
import logging
import threading
import socket
# 配置日志
logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger('pymodbus')
log.setLevel(logging.DEBUG)
# 创建一个自动递增的寄存器值
def create_auto_increment_block(start_value, size):
log.debug(f"Creating auto increment block with start value {start_value} and size {size}")
return ModbusSequentialDataBlock(0, [start_value + i for i in range(size)])
# 初始化数据存储区
store = ModbusSlaveContext(
di=ModbusSequentialDataBlock(0, [0]*10), # 离散输入 (示例值)
co=ModbusSequentialDataBlock(0, [0]*10), # 线圈 (示例值)
hr=create_auto_increment_block(0, 100), # 保持寄存器
ir=ModbusSequentialDataBlock(0, [0]*10) # 输入寄存器 (示例值)
)
context = ModbusServerContext(slaves=store, single=True)
# 设置设备标识
identity = ModbusDeviceIdentification()
identity.VendorName = 'pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/riptideio/pymodbus/'
identity.ProductName = 'pymodbus Server'
identity.ModelName = 'pymodbus Server'
identity.MajorMinorRevision = '1.0'
class CustomModbusTcpServer(ModbusTcpServer):
def handle(self):
try:
log.debug(f"Client Connected [{self.client_address}]")
super().handle()
except Exception as e:
log.error(f"Error handling client {self.client_address}: {e}")
finally:
log.debug(f"Client Disconnected [{self.client_address}]")
def run_server(port):
log.debug(f"Starting Modbus TCP server on port {port}...")
try:
server = CustomModbusTcpServer(context, identity=identity, address=("10.245.3.9", port), framer=ModbusSocketFramer)
server.serve_forever()
except Exception as e:
log.error(f"Error starting Modbus TCP server on port {port}: {e}")
log.debug(f"Modbus TCP server on port {port} is running.")
# 在单独的线程中启动服务器
for port in range(502, 602): # 从502到601共100个端口
server_thread = threading.Thread(target=run_server, args=(port,))
server_thread.start()
# 确保代码执行到这里
print("Modbus TCP servers setup initiated.")
# 确认端口是否绑定成功
for port in range(502, 602): # 从502到601共100个端口
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex(('10.245.3.9', port))
if result == 0:
print(f"Port {port} is open and listening.")
else:
print(f"Port {port} is not open.")
sock.close()
说明:
1、10.245.3.9为本地电脑IP地址;
2、模拟端口从502到601共100个端口;
3、模拟的每台设备有100个寄存器,默认寄存器值自动递增;