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

推荐订阅源

Application and Cybersecurity Blog
Application and Cybersecurity Blog
The Register - Security
The Register - Security
V
Visual Studio Blog
aimingoo的专栏
aimingoo的专栏
Stack Overflow Blog
Stack Overflow Blog
IT之家
IT之家
量子位
C
Check Point Blog
博客园 - 【当耐特】
小众软件
小众软件
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
雷峰网
雷峰网
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Microsoft Azure Blog
Microsoft Azure Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Engineering at Meta
Engineering at Meta
Recorded Future
Recorded Future
The Last Watchdog
The Last Watchdog
博客园 - Franky
N
Netflix TechBlog - Medium
Webroot Blog
Webroot Blog
A
About on SuperTechFans
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
D
Docker
S
Security Affairs
T
The Blog of Author Tim Ferriss
F
Fortinet All Blogs
Blog — PlanetScale
Blog — PlanetScale
V2EX - 技术
V2EX - 技术
Jina AI
Jina AI
Help Net Security
Help Net Security
L
LangChain Blog
P
Proofpoint News Feed
The Cloudflare Blog
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
Schneier on Security
Schneier on Security
Recent Announcements
Recent Announcements
Attack and Defense Labs
Attack and Defense Labs
云风的 BLOG
云风的 BLOG
V
Vulnerabilities – Threatpost
Microsoft Security Blog
Microsoft Security Blog
H
Heimdal Security Blog
P
Proofpoint News Feed
O
OpenAI News
H
Help Net Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
爱范儿
爱范儿
Security Archives - TechRepublic
Security Archives - TechRepublic

博客园 - 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.")