惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
F
Fortinet All Blogs
博客园_首页
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
D
DataBreaches.Net
aimingoo的专栏
aimingoo的专栏
爱范儿
爱范儿
B
Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
N
Netflix TechBlog - Medium
阮一峰的网络日志
阮一峰的网络日志
P
Proofpoint News Feed
D
Docker
Engineering at Meta
Engineering at Meta
大猫的无限游戏
大猫的无限游戏
The Cloudflare Blog
罗磊的独立博客
云风的 BLOG
云风的 BLOG
Microsoft Azure Blog
Microsoft Azure Blog
T
The Exploit Database - CXSecurity.com
博客园 - 三生石上(FineUI控件)
量子位
The Last Watchdog
The Last Watchdog
MyScale Blog
MyScale Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
The Blog of Author Tim Ferriss
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
小众软件
小众软件
Cloudbric
Cloudbric
博客园 - 司徒正美
H
Help Net Security
人人都是产品经理
人人都是产品经理
Application and Cybersecurity Blog
Application and Cybersecurity Blog
L
LangChain Blog
Latest news
Latest news
M
MIT News - Artificial intelligence
T
Threat Research - Cisco Blogs
博客园 - Franky
S
Security Affairs
W
WeLiveSecurity
F
Full Disclosure
Know Your Adversary
Know Your Adversary
Google DeepMind News
Google DeepMind News
The Hacker News
The Hacker News
Cyberwarzone
Cyberwarzone
美团技术团队
PCI Perspectives
PCI Perspectives
C
Check Point Blog
Spread Privacy
Spread Privacy

博客园 - sunny_2016

核聚:雷·达里奥的达成目标5步法 英语发单规则一 英语学习三 英语学习笔记二 英语学习笔记一 modbus协议 OPC UA协议学习笔记 限制ssh非法登录 linux添加hosts.deny文件 jmeter的tcp请求示例发送16进制报文 pymodbus模拟modbus slave从站(二) secure crt使用ssh密钥登录提示未知文件格式 专业的通讯调试工具或者平台有哪些 centos7.9上面卸载中文语言包和中文字体重新安装 linux centos7.9 中文乱码 linux pkill命令的坑 Windows 11 主机上建立反向隧道,实现服务端连接内网客户端主机 互联网上的高危IP,一直在尝试sshd破解 通过/etc/hosts.deny限制一个网段的 SSH 登录尝试 linux查询近8小时ssh登录失败的ip转换为hosts.deny格式打印 多系统集成分析——ERP与OA、PLM、MES、CRM、WMS、SRM、HR ERP也有库存管理、生产管理、流程审批,为什么还要上WMS、MES和OA? gitlab流水线执行发布提示: No such file or directory gitlab-runner注册完提示:New runner. Has not connected yet(新的Runner,尚未连接) 电池片组件生产工艺流程
使用python的pymodbus实现modbus slave 模拟从站一
sunny_2016 · 2026-01-20 · via 博客园 - sunny_2016
import asyncio
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.server import StartAsyncTcpServer
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadBuilder
from aiohttp import web

# ===== 配置 =====
SERVER_IP = "0.0.0.0"
PORTS = [5020, 5021, 5022]
REGISTER_SIZE = 100

slave_contexts = {}
modbus_server_tasks = [] # ← 保存 server task 引用

def create_initial_holding_registers(size=100):
builder = BinaryPayloadBuilder(byteorder=Endian.BIG, wordorder=Endian.BIG)
for i in range(size):
builder.add_16bit_uint(i * 10 + 100)
return builder.to_registers()

async def run_modbus_slave(port):
print(f"[Modbus] Starting slave on port {port}...")

# 创建单个从站的数据存储
slave_store = ModbusSlaveContext(zero_mode=True)
initial_regs = create_initial_holding_registers(REGISTER_SIZE)
slave_store.setValues(3, 0, initial_regs) # 功能码 3 (Holding Registers)

# ✅ 关键:用 ModbusServerContext 包装,指定 unit ID(默认 0)
server_context = ModbusServerContext(slaves=slave_store, single=True)

# 保存到全局(供 HTTP API 使用)
slave_contexts[port] = slave_store # 注意:保存的是 slave_store,不是 server_context

# 启动服务器
server, task = await StartAsyncTcpServer(
context=server_context, # ← 传入包装后的 context
address=(SERVER_IP, port)
)

# 保存 task 引用,防止被 GC 回收
modbus_server_tasks.append(task)
print(f"[Modbus] Slave on port {port} is running.")

# ===== HTTP API =====
async def handle_write_register(request):
try:
data = await request.json()
port = int(data["port"])
address = int(data["address"])
value = int(data["value"])

if port not in slave_contexts:
return web.json_response({"error": f"Port {port} not found"}, status=404)
if not (0 <= address < REGISTER_SIZE):
return web.json_response({"error": f"Address must be 0-{REGISTER_SIZE - 1}"}, status=400)
if not (0 <= value <= 65535):
return web.json_response({"error": "Value must be 0-65535"}, status=400)

slave_contexts[port].setValues(3, address, [value])
return web.json_response({"success": True})
except Exception as e:
return web.json_response({"error": str(e)}, status=400)

async def handle_list_ports(request):
return web.json_response({"ports": list(slave_contexts.keys())})

async def start_http_server():
app = web.Application()
app.router.add_post("/write", handle_write_register)
app.router.add_get("/ports", handle_list_ports)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, "0.0.0.0", 8080)
await site.start()
print("[HTTP] Server running on http://0.0.0.0:8080")

# ===== Main =====
async def main():
print("🚀 Starting Modbus Slaves and HTTP API...")

# 启动所有 Modbus 从站
for port in PORTS:
asyncio.create_task(run_modbus_slave(port))

# 启动 HTTP 服务器
await start_http_server()

print("✅ All services started. Press Ctrl+C to stop.")
try:
# 永久等待(因为 Modbus server task 已在后台运行)
await asyncio.Event().wait()
except KeyboardInterrupt:
print("\n🛑 Shutting down...")

if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n🛑 Exited.")