PlcSimulator.Core
2.2.9
dotnet add package PlcSimulator.Core --version 2.2.9
NuGet\Install-Package PlcSimulator.Core -Version 2.2.9
<PackageReference Include="PlcSimulator.Core" Version="2.2.9" />
<PackageVersion Include="PlcSimulator.Core" Version="2.2.9" />
<PackageReference Include="PlcSimulator.Core" />
paket add PlcSimulator.Core --version 2.2.9
#r "nuget: PlcSimulator.Core, 2.2.9"
#:package PlcSimulator.Core@2.2.9
#addin nuget:?package=PlcSimulator.Core&version=2.2.9
#tool nuget:?package=PlcSimulator.Core&version=2.2.9
PLC Simulator - 工业级全协议仿真器
这是一个基于 .NET(核心库 netstandard2.0、测试与工具链 net10.0)开发的高性能 PLC 仿真服务器,旨在为工业自动化领域的软件开发、测试和教学提供一个轻量级、跨平台的仿真环境(完美支持 MacOS)。
🌟 核心特性
- 全协议支持:内置西门子 (S7)、三菱 (MC/A-1E)、欧姆龙 (FINS)、罗克韦尔 (CIP)、Modbus TCP 及 BACnet/IP 等协议仿真。
协议清单以
ProtocolCatalog为准,当前共 42 种(含 TCP/UDP/串行)。 ⚠️ 平台差异:macOS 上实测 37 种可启动、5 种受限(三菱 MC 的 5000 端口被 AirPlay 占用、 串口类 IEC101/DNP3/Modbus-RTU 无串口设备、BACnet 需 UDP 模式)。 启动后用critical_failed与failed_servers字段确认实际可用协议。 - 吞吐能力(实测,非标称):S7 协议面单实例实测——
单连接顺序读约 2,700~4,600 RPS(受往返时延限制);
4 连接并发约 15,000~20,000 RPS、8 连接并发约 12,000~27,000 RPS。
⇒ 「10,000+ RPS」需多连接并发方可达成,单连接达不到。
可复现基准见
scripts/benchmark-s7-throughput.sh(macOS/Apple Silicon 实测口径)。 - 统一内存模型:所有协议共享同一块寄存器空间——7 个固定区各 64KB
(M/I/Q/T/C/AI/AQ),外加按需创建的 DB 块(每块 64KB)。支持协议间数据透明互通。
字节序约定(重要):内存按**规范序(大端 / ABCD)**存放,唯一权威声明是
PlcMemory.CanonicalDataFormat,控制面与类型化访问器(ReadWord/WriteWords等) 均由它参数化(Docs/247)。 各协议服务器不得把内存字节裸透传上线——透传只对大端线序协议(S7/Modbus/FINS 等)成立; 小端线序协议(三菱 MC、AB CIP、Beckhoff ADS 等)必须在服务器内声明各自的线序 codec (参照MelsecMcServer.McWireCodec = RegularByteTransform(DataFormat.DCBA)), 并经PlcMemory类型化访问器 ⇄ 线序 codec 转换。 跨路径回归锁见CrossProtocolByteOrderTests(S7/Modbus)与MelsecMcCrossTests(HSL 真客户端,修复前 11/11 复现 -11772 镜像值)。 详见Docs/244、Docs/247。 - 生产级兼容性:支持西门子 S7-200 SMART/1200/1500 模型;DB 块编号不受 10000 限制
(2026-10-02 实测
DB10001、DB19999均可正常读写)。 ⚠️ 但 DB 块数量上限为 1000 块(PlcMemory.MaxDbBlockCount,防内存耗尽),超出时明确抛错。 - 跨平台运行:原生支持 MacOS、Linux 和 Windows。
🛡️ 安全特性
- 报文校验: 部分协议服务器设有 count/长度上限校验,例如三菱 MC/三菱 A1E/欧姆龙 HostLink
均为 2048 点(
MaxMcRequestCount等常量);Allen-Bradley 校验 CIP 路径边界。 ⚠️ 并非全部服务器都有显式上限(2026-10-02 实测:38 个服务器文件中 14 个含 count/长度上限校验), 如 BACnet 未做此类校验。使用方不应假定所有协议等强防护。 - 全局异常处理: CLI/UI 均配置 UnhandledException 处理,防止静默崩溃。
- 敏感信息保护:
.qwen/、.qoder/、.roo/、.serena/等已加入.gitignore(git check-ignore实证;其历史提交内容仅含权限白名单、无密钥)。 ⚠️ 已知问题:HslCommunication 的商业授权码硬编码在源码中且已提交进本公开仓库 (自 2026-03-04 起)。该码是功能性依赖(缺失时 HSL 组件 24 小时后失效), 处置需产品决策。详见Docs/246§六。
🧪 测试覆盖
- 测试框架: xUnit + FluentAssertions
- 测试数量: 1341 个测试全部通过 / 0 失败 / 6 跳过(2026-10-02 实测:
dotnet test src/PlcSimulator.Test/PlcSimulator.Test.csproj,约 110 秒) - 测试策略: 部分用例通过反射调用 private 方法;子集为 loopback 自连(绑定 127.0.0.1 随机端口,
并非完全无网络——该子集含
S7ServerTests等绑定 loopback socket 的用例), 2026-10-02 实测 262 个用例约 78 秒、不依赖外部设备或外网。 - 覆盖率: ⚠️ 暂无机器化口径——仓库当前无 coverage 产物与覆盖率门禁,
故不声明具体覆盖率数字。协议报文解析的边界用例较密集,但未做量化统计。
(如需该指标,应先引入覆盖率采集与门禁,见
Docs/246)
运行测试:
# 单元测试(无网络依赖)
dotnet test src/PlcSimulator.Test/PlcSimulator.Test.csproj \
--filter "FullyQualifiedName~PlcAddressHelper|FullyQualifiedName~PlcMemory|FullyQualifiedName~S7ServerTests|FullyQualifiedName~ModbusAddressResolver|FullyQualifiedName~MelsecMcServer|FullyQualifiedName~OmronFinsServer"
# 集成测试(需要网络)
dotnet test src/PlcSimulator.Test/PlcSimulator.Test.csproj
📐 工程化规范
- 代码风格:
.editorconfig统一 C# 命名约定、缩进、换行、模式匹配偏好 - SDK 版本:
global.json锁定 .NET 10.0,防止版本漂移 - 构建属性:
Directory.Build.props统一 Nullable/ImplicitUsings/版本号
📁 项目结构
src/PlcSimulator.Core: 核心逻辑、统一内存模型 (PlcMemory) 和服务器接口。src/PlcSimulator.Lite: 协议实现与统一内存模型(PlcMemory、PlcTypeConverter、各协议服务器)。src/PlcSimulator.Cli: 控制台交互式启动程序。src/PlcSimulator.Grpc: gRPC 控制面(proto 定义与生成代码)。src/S7Simulator.Standalone: 独立的 S7 仿真控制台(s7sim工具,不含 gRPC)。src/PlcSimulator.Test: 基于HslCommunication的自动化测试套件。
🚀 快速开始
1. 编译项目
使用 .NET 8 SDK 进行编译:
dotnet build src/PlcSimulator.sln
1.1 UI Linux 桌面支持开关(重要)
src/PlcSimulator.UI/PlcSimulator.UI.csproj 增加了 EnableLinuxDesktopSupport 开关:
- 默认值:
false- 默认正式版构建不引入 Linux X11 桌面链路(避免额外
DBus/X11依赖风险)。
- 默认正式版构建不引入 Linux X11 桌面链路(避免额外
- 需要 Linux 桌面运行时,显式开启:
dotnet build src/PlcSimulator.UI/PlcSimulator.UI.csproj -v minimal /p:EnableLinuxDesktopSupport=true
- 运行时行为:
- macOS:
UseAvaloniaNative() - Windows:
UseWin32() - Linux:仅在启用开关的构建下走
UseX11()
- macOS:
2. 启动仿真服务器
dotnet run --project src/PlcSimulator.Cli/PlcSimulator.Cli.csproj
启动后在 PlcSim> 提示符下输入 start 即可开启所有协议监听。
3. 运行自动化测试
我们提供了基于 HslCommunication 的压力与兼容性测试:
dotnet run --project src/PlcSimulator.Test/PlcSimulator.Test.csproj
🛠 协议与端口映射 (MacOS 兼容)
| 协议 | 端口 | 内存映射地址示例 |
|---|---|---|
| 西门子 S7 | 102 | DB1.0, M100, I0, Q0 |
| 三菱 MC 3E | 5000 | D100, M0 |
| 三菱 MC 1E | 5001 | D0 (旧款 A 系列) |
| 欧姆龙 FINS | 9600 | D100 (映射至 DB1) |
| Modbus TCP | 502 | 00001, 10001, 30001, 40001 |
| BACnet/IP | 47808 | AnalogValue:1 (映射至 DB1 偏移 4) |
| 罗克韦尔 AB CIP | 44818 | TAGA / CIP 映射 |
| Modbus RTU over TCP | 1502 | 与 MBAP 502 分口;错站静默 |
| HART-IP | 5094 | Cmd3 读 PV(子集) |
| Omron HostLink(TCP) | 9600 | 与 FinsTcp 同口互斥;主路径 DM |
| MTConnect Agent | 5005 | JSON /current(非标准 XML) |
Modbus 地址区支持说明
当前 Modbus TCP 仿真已支持标准四大地址区:
| 地址区 | 功能码 | 说明 | 内部映射 |
|---|---|---|---|
0xxxx |
01 / 05 / 15 |
Coil,支持读/写 | DB3 偏移 0 起的位区 |
1xxxx |
02 |
Discrete Input,只读 | DB3 偏移 1024 起的位区 |
3xxxx |
04 |
Input Register,只读 | DB2 偏移 0 起 |
4xxxx |
03 / 06 / 16 |
Holding Register,支持读/写 | DB1 偏移 0 起 |
说明:
30001和40001是相互独立的两块寄存器区,不共享同一内存。00001与10001也是独立位区,不共享同一字节偏移。- UI/工作台地址输入也支持
HR1 / IR1 / COIL1 / DI1这类前缀形式,便于和不同主站软件的习惯保持一致。 - 若使用低位端口
502,在 macOS/Linux 上仍需管理员权限或改用高位端口。
注意:在 MacOS/Linux 上,
102/502属于特权端口。无管理员权限时请使用sudo,或通过 CLI 参数改用高位端口(如--s7-port 1102 --modbus-port 1502;如需多实例也可使用--melsec-port/--melsec-a1e-port/--omron-port/--ab-port/--bacnet-port覆写端口)。
🧱 扩展新协议
由于采用了高度抽象的 IPlcServer 接口和统一的 PlcMemory,扩展新协议非常简单:
- 在
Protocols项目下新建类并实现IPlcServer。 - 在
Start()中开启监听并解析报文。 - 通过
_memory.Read()或_memory.Write()与全局内存交互。 - 在
Program.cs中注册该服务器即可。
📎 与 ZL.IotHub 联调口径(Docs/207)
权威细节见 Docs/207_ZL.IotHub对照仿真补强方案_20260909.md §9。发版对外口径摘录如下。
可宣称
- IotHub Native/HSL TCP/HTTP 主路径本机联调:本批新增
modbus-rtu-over-tcp/hart-ip/omron-host-link/mtconnect,以及既有 S7/MC/FINS/ADS/Fatek/FxLinks/AB/REST 等 - 帧级/TCP/CLI 门禁可复现:
scripts/verify_iothub_protocol_loop.sh(L1)→verify_iothub_protocol_tcp.sh(L2)→iothub_cross_smoke.sh(L3;EXTRA=1可选 S7/MC/FinsTcp) - HostLink 与 FinsTcp 同口会被硬拦;mtconnect 按 JSON AgentUrl 联调
- 汇川/台达走 Modbus TCP + 驱动侧地址映射(仿真不做服务端二次翻译)
不可宣称
- 已与 IotHub 全部 Native 键做完驱动包端到端自动化
- 松下
panasonic-mewtocol串口驱动已与仿真互通(仿真为 TCP:9090) - Hart 支持全部命令/写;HostLink 覆盖全部 FINS 区与 EM bank
- 标准 MTConnect XML
/currentAgent - 仿真器服务端二次翻译 Inovance/Delta 符号地址
默认端口以 ProtocolDefaultPorts 为准(melsec-mc 仿真默认 5000,与部分 IotHub 文档 6000 不一致时请显式 --ports)。
📚 补充文档
- IotHub 对照仿真方案(含缺口矩阵):
Docs/207_ZL.IotHub对照仿真补强方案_20260909.md - CLI 语义命令与 JSON 协议:
Docs/PlcSimulator.Cli-语义命令与JSON协议.md - CLI-Anything 使用说明:
agent-harness/cli_anything/plcsimulator/USAGE.zh-CN.md - AI 评选叙事建议:
Docs/14-AI评选叙事与落地价值.md
坚持简洁、高效、稳定。本项目是从电检项目演化而来的全领域工控仿真工具。
📄 许可证
本项目采用 Apache License 2.0,全文见仓库根目录 LICENSE。
通过 NuGet 分发的包已在 nuspec 中声明 <license type="expression">Apache-2.0</license>。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- BACnet (>= 2.0.4)
- Google.Protobuf (>= 3.35.1)
- MQTTnet (>= 4.3.6.1152)
- NModbus (>= 3.0.81)
- OPCFoundation.NetStandard.Opc.Ua (>= 1.5.378.134)
- PlcSimulator.Lite (>= 2.2.9)
- System.IO.Ports (>= 8.0.0)
- System.Text.Json (>= 10.0.2)
- ZL.Watchdog (>= 1.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.