当前位置: 首页 > wzjs >正文

淘宝联盟返利网站怎么做市场调研的重要性

淘宝联盟返利网站怎么做,市场调研的重要性,顺企网查企业电话,wordpress修改注册🚀🔧【实战】基于 ABP vNext 构建高可用 S7 协议采集平台(西门子 PLC 通信全流程)📊 📑 目录 🚀🔧【实战】基于 ABP vNext 构建高可用 S7 协议采集平台(西门子 PLC 通信全…

🚀🔧【实战】基于 ABP vNext 构建高可用 S7 协议采集平台(西门子 PLC 通信全流程)📊


📑 目录

  • 🚀🔧【实战】基于 ABP vNext 构建高可用 S7 协议采集平台(西门子 PLC 通信全流程)📊
      • 一、背景与目标 🎯
      • 二、系统架构与技术栈 🏗️
        • 系统架构概览流程图 🏗️
      • 三、配置系统设计 ⚙️
        • 1. appsettings.json
        • 2. 配置类
        • 3. 热加载与 DI 注册(Program.cs)
      • 四、线程安全通信连接池设计 🔒
        • 连接池租借/归还流程图 🔒
      • 五、后台采集 Worker 实现 🤖
        • Worker 周期执行流程图 🤖
      • 六、重试与熔断策略注入 🔄
        • 重试与熔断策略流程图 🔄
      • 七、健康检查与指标上报 📈
      • 八、Docker 容器化部署建议 🐳
        • Docker 多阶段构建流程图 🐳
      • 九、总结与最佳实践清单 📝
      • 十、参考资料 📚


一、背景与目标 🎯

在工业自动化项目中,西门子 S7 系列 PLC 广泛用于设备控制与数据采集。传统 OPC 通信方式配置繁琐、延迟高,难以胜任现代 IoT 场景。

目标:

  • 构建跨平台、配置化的高可用通信平台;
  • 实现多台 PLC 并发采集、统一缓存与错误容忍;
  • 支持部署、监控、容器化与持续运行。

二、系统架构与技术栈 🏗️

系统架构概览流程图 🏗️
基础设施层
业务层
API 层
S7.NetPlus PLC 连接
Redis 缓存
Prometheus/ELK
PlcPollingWorker
PlcConnectionManager
IDistributedCache
HealthChecks
HTTP 接口
Worker 任务调度
模块技术选型
框架ABP vNext (.NET 8)
通信S7.NetPlus
配置IOptionsSnapshot + reloadOnChange + 环境变量
重试Polly (Retry + CircuitBreaker)
后台任务AbpBackgroundWorker
健康检查ASP.NET Core HealthChecks
日志Serilog + 结构化日志
容器部署Docker 多阶段构建

三、配置系统设计 ⚙️

1. appsettings.json
{"PlcOptions": {"IntervalSeconds": 5,"Devices": [{"DeviceId": "PLC-1","CpuType": "S7300","Ip": "192.168.1.100","Rack": 0,"Slot": 2,"Address": "DB1.DBW0"}]}
}
2. 配置类
public class PlcDeviceOptions
{public string DeviceId { get; set; } = null!;public string CpuType   { get; set; } = "S7300";public string Ip        { get; set; } = null!;public int    Rack      { get; set; }public int    Slot      { get; set; }public string Address   { get; set; } = null!;
}public class PlcOptions
{public int                  IntervalSeconds { get; set; } = 5;public List<PlcDeviceOptions> Devices       { get; set; } = new();
}
3. 热加载与 DI 注册(Program.cs)
var builder = WebApplication.CreateBuilder(args);// 配置源:JSON + 环境变量
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).AddEnvironmentVariables();// 注册配置
builder.Services.Configure<PlcOptions>(builder.Configuration.GetSection("PlcOptions"));// 注册核心服务
builder.Services.AddSingleton<PlcConnectionManager>();
builder.Services.AddPolicyRegistry().Add("PlcRetry",Policy.Handle<Exception>().RetryAsync(3, onRetry: (ex, cnt) =>builder.Logging.CreateLogger("Polly").LogWarning(ex, "第{Attempt}次重试失败", cnt)).CircuitBreakerAsync(handledEventsAllowedBeforeBreaking: 5,durationOfBreak: TimeSpan.FromSeconds(30),onBreak: (ex, ts) =>builder.Logging.CreateLogger("Polly").LogError(ex, "熔断开启,持续{Break}s", ts.TotalSeconds),onReset: () =>builder.Logging.CreateLogger("Polly").LogInformation("熔断恢复")));// 注册 ABP Worker 和 HealthChecks
builder.Services.AddBackgroundWorker<PlcPollingWorker>();
builder.Services.AddHealthChecks().AddCheck<PlcHealthCheck>("plc_check");var app = builder.Build();// 映射健康检查端点
app.MapHealthChecks("/health");// 优雅停机:释放连接池
app.Lifetime.ApplicationStopping.Register(async () =>
{await app.Services.GetRequiredService<PlcConnectionManager>().DisposeAsync();
});app.Run();

四、线程安全通信连接池设计 🔒

public class PlcConnectionManager : IAsyncDisposable
{// key → (信号量, 已打开的 Plc 实例)private readonly ConcurrentDictionary<string, (SemaphoreSlim Lock, Plc Plc)> _connections = new();/// <summary>/// 租借一个 PLC 实例(线程安全)/// </summary>public async Task<Plc> RentAsync(PlcDeviceOptions opt){var key = opt.DeviceId;var entry = _connections.GetOrAdd(key, _ =>{var plc = new Plc(Enum.Parse<CpuType>(opt.CpuType, ignoreCase: true),opt.Ip, opt.Rack, opt.Slot);try{plc.Open();}catch{// 打开失败,移除池中该项_connections.TryRemove(key, out _);throw;}return (new SemaphoreSlim(1, 1), plc);});// 等待获取信号量await entry.Lock.WaitAsync();return entry.Plc;}/// <summary>/// 归还租借的实例/// </summary>public void Return(string deviceId){if (_connections.TryGetValue(deviceId, out var entry)){entry.Lock.Release();}}/// <summary>/// 优雅释放所有资源/// </summary>public async ValueTask DisposeAsync(){foreach (var kv in _connections.Values){var sema = kv.Lock;await sema.WaitAsync();       // 确保没有并发占用kv.Plc.Close();sema.Release();sema.Dispose();}}/// <summary>/// 获取所有断线设备列表/// </summary>public IEnumerable<string> GetDisconnectedDevices() =>_connections.Where(kv => !kv.Value.Plc.IsConnected).Select(kv => kv.Key);
}
连接池租借/归还流程图 🔒
开始 RentAsync(Device)
池中存在?
获取 (Semaphore, Plc)
创建新 Plc 实例并 Open()
存入 ConcurrentDictionary
Await Semaphore.WaitAsync()
返回 Plc 给调用方
调用完成后执行 Return(DeviceId)
Semaphore.Release()
流程结束

五、后台采集 Worker 实现 🤖

public class PlcPollingWorker : AsyncPeriodicBackgroundWorkerBase
{private readonly IOptionsSnapshot<PlcOptions> _options;private readonly PlcConnectionManager          _connMgr;private readonly ILogger<PlcPollingWorker>     _logger;private readonly IDistributedCache<string>     _cache;private readonly AsyncPolicy                   _retry;public PlcPollingWorker(AbpTimer                       timer,IOptionsSnapshot<PlcOptions>   options,PlcConnectionManager           connMgr,IDistributedCache<string>      cache,IPolicyRegistry<string>        policyRegistry,ILogger<PlcPollingWorker>      logger) : base(timer){_options = options;_connMgr  = connMgr;_cache    = cache;_retry    = policyRegistry.Get<AsyncPolicy>("PlcRetry");_logger   = logger;Timer.PeriodTimeSpan = TimeSpan.FromSeconds(_options.Value.IntervalSeconds);}protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext ctx){foreach (var dev in _options.Value.Devices){using var scope = _logger.BeginScope("Device:{DeviceId}", dev.DeviceId);Plc plc = null!;try{plc = await _connMgr.RentAsync(dev);// 异步执行阻塞调用var val = await _retry.ExecuteAsync(() =>Task.Run(() => (short)plc.Read(dev.Address)));await _cache.SetAsync($"Plc:{dev.DeviceId}:Value",val.ToString(),new DistributedCacheEntryOptions{SlidingExpiration = TimeSpan.FromSeconds(30)});_logger.LogInformation("{Device} OK - {Val}", dev.DeviceId, val);}catch (Exception ex){_logger.LogWarning(ex, "Device {DeviceId} 读取失败", dev.DeviceId);}finally{if (plc is not null){_connMgr.Return(dev.DeviceId);}}}}
}
Worker 周期执行流程图 🤖
Timer PlcPollingWorker PlcConnectionManager PollyRetryPolicy IDistributedCache ILogger 定时触发 DoWorkAsync() RentAsync(dev) 返回 plc 实例 ExecuteAsync(Read(dev.Address)) 返回 value SetAsync(key, value) LogInformation(...) Return(dev) loop [遍历每台设备] LogWarning(...) alt [出现异常] Timer PlcPollingWorker PlcConnectionManager PollyRetryPolicy IDistributedCache ILogger

六、重试与熔断策略注入 🔄

// 在 Program.cs 中已注册:
builder.Services.AddPolicyRegistry().Add("PlcRetry",Policy.Handle<Exception>().RetryAsync(3, onRetry: (ex, cnt) =>logger.LogWarning(ex, "第{Attempt}次重试失败", cnt)).CircuitBreakerAsync(handledEventsAllowedBeforeBreaking: 5,durationOfBreak: TimeSpan.FromSeconds(30),onBreak: (ex, ts) =>logger.LogError(ex, "熔断开启,持续{Break}s", ts.TotalSeconds),onReset: () =>logger.LogInformation("熔断已恢复")));
重试与熔断策略流程图 🔄
成功
失败
失败
失败
重试下一次
RetryAsync 第1次
返回结果
RetryAsync 第2次
RetryAsync 第3次
CircuitBreaker 计数 +1
失败次数 ≥5?
熔断开启: 30s
拒绝所有后续调用
onReset 恢复后重置计数

七、健康检查与指标上报 📈

public class PlcHealthCheck : IHealthCheck
{private readonly PlcConnectionManager _manager;public PlcHealthCheck(PlcConnectionManager manager) =>_manager = manager;public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext ctx,CancellationToken    ct = default){var down = _manager.GetDisconnectedDevices().ToList();return Task.FromResult(down.Any()? HealthCheckResult.Unhealthy($"失联设备: {string.Join(", ", down)}"): HealthCheckResult.Healthy("所有 PLC 均连接正常"));}
}
  • 已通过 app.MapHealthChecks("/health") 暴露
  • 可集成 Prometheus/OpenTelemetry 暴露 /metrics

八、Docker 容器化部署建议 🐳

# 构建阶段
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app# 运行阶段
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app ./# 安装健康探针依赖并清理
RUN apt-get update \&& apt-get install -y --no-install-recommends curl \&& rm -rf /var/lib/apt/lists/*HEALTHCHECK --interval=10s \CMD curl --fail http://localhost:5000/health || exit 1ENTRYPOINT ["dotnet", "S7Reader.HttpApi.Host.dll"]
Docker 多阶段构建流程图 🐳
Runtime 阶段
COPY /app
FROM aspnet:8.0
apt-get install curl
HEALTHCHECK
ENTRYPOINT dotnet S7Reader.HttpApi.Host.dll
Build 阶段
dotnet restore
checkout 源码
dotnet build
dotnet publish -o /app

九、总结与最佳实践清单 📝

分类实践建议
配置管理IOptionsSnapshot + reloadOnChange + 环境变量,实现热更新
DI 注册AddSingleton()
AddBackgroundWorker()
AddHealthChecks()/MapHealthChecks
连接池设计租借/归还模式 + 异常清理
IAsyncDisposable 优雅关闭
异步与容错Task.Run 封装阻塞调用
Polly Retry + CircuitBreaker
日志 onBreak/onReset
后台调度ABP Worker 框架周期执行
外层全捕异常,保持服务持续运行
健康监控精准检测每台设备状态
HealthChecks + Prometheus/OpenTelemetry
容器部署Docker 多阶段构建
无冗余依赖镜像
标准 HEALTHCHECK
优雅停机ApplicationStopping.ReleaseAsync → DisposeAsync
日志可视化Serilog 结构化 + BeginScope “设备ID”上下文

十、参考资料 📚

  • S7.NetPlus GitHub
  • ABP vNext 官方文档
  • Polly 异常处理库
  • ASP.NET Core HealthChecks
  • Serilog 结构化日志

http://www.dtcms.com/wzjs/397890.html

相关文章:

  • 网站建设实训站长工具忘忧草社区
  • 做网站常用什么软件站长查询工具
  • 做一个国外的网站搜索网站大全
  • 极乐宝盒网站建设百度客服人工在线咨询
  • 如何不花钱开发网站seo 网站推广
  • 即墨网站建设哪里有网络seo是什么
  • 百度飙风算法 小网站免费新闻源发布平台
  • 手机网站怎么建软文广告文案
  • excel做网站页面布局seo优化的主要任务包括
  • 云南网站做的好的公司aso推广
  • 合肥建设管理学院网站百度手机助手最新版下载
  • 网站群建设技术方案百度账号安全中心官网
  • 昆山网页设计报价seo推广百度百科
  • 如何建设网站简答题北京网站sem、seo
  • 做徒步网站怎么样网站策划方案
  • 建设外贸网站要多少钱网站设计与制作公司
  • 做配音的网站百度付费问答平台
  • 网络培训学校排名关键词优化公司哪家效果好
  • 做网站的公司吉林服务器ip域名解析
  • 如何做简单的网站线上营销技巧和营销方法
  • 云南网站建设公司排名济南seo优化外包服务公司
  • 万网域名指向网站广点通广告投放平台
  • 长沙做网站那家好新手电商运营从哪开始学
  • 绿色健康网站模板百度搜索排名优化哪家好
  • .net 网站生成安装文件目录吉林网站推广公司
  • 西宁贴吧班级优化大师免费下载
  • 南京网站建设 雷仁网互联网营销策划方案
  • 交互设计专业世界大学排名潜江seo
  • 网站建设什么公司专业网站建设的流程是什么
  • 邯郸制作网站的公司国外推广网站