在aspNetCore webApi中使用System.Threading.Channels 建立一个高性能的Plc通信库

    public interface IS7ConnService
    {
        void ConnPlc(string myIp, int dbNum, int startByte);


        bool MyIsConnected
        {
            get;
        }

        Plc S7Plc { get; }
    }
    public class DB33Ioc : INotifyPropertyChanged
    {
        private bool b1;
        private bool b2;
        public bool B1
        {
            get => b1;
            set
            {
                if (b1 != value && value == true)
                {
                    NotifyPropertyChanged(nameof(B1));
                }
                b1 = value;
            }
        }

        public bool B2
        {
            get => b2;
            set
            {
                if (b2 != value && value == true)
                {
                    NotifyPropertyChanged(nameof(B2));
                }
                b2 = value;
            }
        }

        public bool B3 { get; set; }
        public short S1 { get; set; }
        public short S2 { get; set; }
        public short S3 { get; set; }

        public float R1 { get; set; }
        public float R2 { get; set; }
        public float R3 { get; set; }


        [S7String(S7StringType.S7String, 30)]
        public string Str { get; set; } = string.Empty;


        public virtual void NotifyPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }




        public event PropertyChangedEventHandler? PropertyChanged;
    }

通信库:

    public class S7NioService<T> : IS7ConnService
        where T : class, new()
    {
        private int errorTimes = 0;

        //private PeriodicTimer timer = new(TimeSpan.FromMilliseconds(100));
        private CancellationTokenSource cts = new();
        public bool MyIsConnected { get; set; }

        public Plc? S7Plc { get; set; }

        private Channel<T> messageChannel;
        private readonly ILogger<S7NioService<T>> logger;
        private T nioData;

        public S7NioService(ILogger<S7NioService<T>> logger, T nioData)
        {
            this.logger = logger;
            this.nioData = nioData;

            var opt = new BoundedChannelOptions(2000)
            {
                FullMode = BoundedChannelFullMode.DropOldest,
                Capacity = 2000
            };
            messageChannel = Channel.CreateBounded<T>(opt);
            Task.Run(async () =>
            {
                await foreach (T item in messageChannel.Reader.ReadAllAsync())
                {
                    CopyProperties(item, this.nioData);
                    //this.nioData = item;
                }
            });
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="myIp">Ip地址</param>
        /// <param name="dbNum">Db号</param>
        /// <param name="startByte">起始字节</param>
        public void ConnPlc(string myIp, int dbNum, int startByte)
        {
            //using PeriodicTimer timer = new(TimeSpan.FromMilliseconds(100));

            Task.Factory.StartNew(
                async () =>
                {
                    using PeriodicTimer timer = new(TimeSpan.FromMilliseconds(100));
                    while (!cts.IsCancellationRequested && await timer.WaitForNextTickAsync())
                    {
                        if (S7Plc == null || !MyIsConnected)
                        {
                            try
                            {
                                S7Plc = new Plc(CpuType.S71500, myIp, 0, 1);
                                S7Plc.Open();
                                S7Plc.ReadTimeout = 620;
                                S7Plc.WriteTimeout = 620;
                                MyIsConnected = S7Plc.IsConnected;
                                if (MyIsConnected)
                                {
                                    logger.LogInformation("PlcSucessConn!");
                                }
                            }
                            catch (Exception ex)
                            {
                                if (errorTimes > 200)
                                {
                                    errorTimes = 0;
                                    logger.LogError("重试连接次数超过200");
                                }
                                errorTimes++;
                                S7Plc?.Close();
                                S7Plc = null;
                                MyIsConnected = false;
                                logger.LogError($"{ex.Message}:{DateTime.Now}");
                                logger.LogError("重连次数:" + errorTimes);
                                await Task.Delay(2000);
                            }
                        }
                        else if (MyIsConnected)
                        {
                            try
                            {
                                MyIsConnected = S7Plc.IsConnected;
                                errorTimes = 0;
                                var dbDataTemp = await S7Plc.ReadClassAsync<T>(dbNum, startByte);
                                //T nioDataTemp = new();
                                //CopyProperties(dbDataTemp, nioDataTemp);
                                if (dbDataTemp != null)
                                {
                                    await messageChannel.Writer.WriteAsync(dbDataTemp);
                                }
                                //messageChannel.Writer.Complete(); //告诉reader 写完成信号
                            }
                            catch (Exception ex)
                            {
                                if (errorTimes > 200)
                                {
                                    errorTimes = 0;
                                    logger.LogError("读取时发生错误次数超过200");
                                }
                                errorTimes++;
                                await Task.Delay(2000);

                                logger.LogError($"读取时发生错误:{ex.Message}:{DateTime.Now}");
                                logger.LogError($"读取时发生错误次数:{errorTimes}");
                                S7Plc.Close();
                                MyIsConnected = false;
                                S7Plc = null;
                            }
                        }
                    }
                },
                cts.Token,
                TaskCreationOptions.LongRunning,
                TaskScheduler.Default
            );
        }
    }

在初始化类调用:

    public class StartupInitializationService : IHostedLifecycleService
    {
        private readonly IS7ConnService s7ConnService;
        private DB33Ioc dB33Ioc;
        private readonly ILogger<StartupInitializationService> logger;
        private readonly SqliteSTRespository<Person> repPerson;
        private readonly IHttpClientFactory clientFactory;

        public StartupInitializationService(
            IS7ConnService s7ConnService,
            DB33Ioc dB33Ioc,
            ILogger<StartupInitializationService> logger,
            SqliteSTRespository<Person> repPerson,
            IHttpClientFactory clientFactory
        )
        {
            this.s7ConnService = s7ConnService;
            this.dB33Ioc = dB33Ioc;
            this.logger = logger;
            this.repPerson = repPerson;
            this.clientFactory = clientFactory;
        }

        /// <summary>
        /// 第二早
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task StartAsync(CancellationToken cancellationToken)
        {
            IConfigurationRoot? buider = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .Build();
            string ip = buider["PlcIp"];
            s7ConnService.ConnPlc(ip, 33, 0);

            dB33Ioc.PropertyChanged += async (s, e) =>
            {
                if (e.PropertyName == "B2")
                {
                    logger.LogWarning("B2被触发!");
                    logger.LogWarning(dB33Ioc.Str);
                }
            };

            //List<Person> persons = new();
            //for (int i = 0; i < 2; i++)
            //{
            //    Person person = new()
            //    {
            //        Age = $"{i + 1}",
            //        Name = $"Tom{i + 1}"
            //    };
            //    persons.Add(person);
            //}

            //var a = repPerson.InsertRange(persons);

            //logger.LogWarning(respositoryFt.GetById(1).PartNum);

            return Task.CompletedTask;
        }

        /// <summary>
        /// 停止后第二
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task StopAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }

        /// <summary>
        /// 启动完成
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        async Task IHostedLifecycleService.StartedAsync(CancellationToken cancellationToken)
        {
            using HttpClient? client = clientFactory.CreateClient();
            client.Timeout = TimeSpan.FromSeconds(20);
            //client.BaseAddress = new Uri(ip);

            var baseRequest = new BaseRequest
            {
                Method = HttpMethod.Post,
                Route = "/api/Test/MyClientTest",
                Parameter = new Person { Age = "19", Name = "xiaoM" }
            };
            //MyHttpClient myHttpClient = new(ip, client);
            MyHttpClient myHttpClient = new(client, "myIp");
            var response = await myHttpClient.ExecuteAsync<Person>(baseRequest);
            JsonSerializerOptions options = new()
            {
                WriteIndented = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            };
            var str = JsonSerializer.Serialize(response, options);
            logger.LogInformation($"started返回值: {str}");
            //double ac = 0;
            //int aaa = 0;
            //short bbb = 0;
            //Interlocked.Exchange(ref ac, 1.5);
            //Interlocked.Exchange(ref aaa , bbb);
            return;
        }

        /// <summary>
        /// 最早
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        Task IHostedLifecycleService.StartingAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }

        /// <summary>
        /// 已经停止
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        Task IHostedLifecycleService.StoppedAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }

        /// <summary>
        /// 停止后第一
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        Task IHostedLifecycleService.StoppingAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
    }


注入Ioc

builder.Services.AddSingleton<DB33Ioc>();
builder.Services.AddSingleton<IS7ConnService, S7NioService<DB33Ioc>>();
builder.Services.AddHostedService<StartupInitializationService>();
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潘诺西亚的火山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值