林豪 左 3 years ago
parent
commit
33c83fd9cf

+ 1 - 36
WCS Pedestal.sln

@@ -7,12 +7,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "框架", "框架", "{43005E
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "项目", "项目", "{9D01B749-E4C4-4AD4-82E1-5C3CA65295E5}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.DbHelper", "WCS.DbHelper\WCS.DbHelper.csproj", "{5178BC6C-A3BF-4B36-A1C6-1B7DC5937474}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.Log", "WCS.Log\WCS.Log.csproj", "{B0A743B0-881E-4997-BE75-B5C4ED4A9BE4}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.Redis", "WCS.RedisHelper\WCS.Redis.csproj", "{A93E66D2-2A49-410C-BDA6-AF0EF230A958}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.Entity", "WCS.Entity\WCS.Entity.csproj", "{E20F0C8A-619A-4D78-835C-909E81338458}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.Core", "WCS.Core\WCS.Core.csproj", "{17CF21B9-84AC-4FB3-9BC1-EF96CF8381CA}"
@@ -21,13 +15,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.Entity.Protocol", "WCS.
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.Service", "WCS.Service\WCS.Service.csproj", "{54AF53DB-5A76-48D4-BD5F-F79D123DE1CB}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.Virtual_PLC", "WCS.Virtual_PLC\WCS.Virtual_PLC.csproj", "{A8557AE8-BDBE-4508-AA58-C7E7F90EFDD2}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.WebApi", "WCS.WebApi\WCS.WebApi.csproj", "{6FE23C07-7FFC-4CF7-A889-9B62957E0BA5}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.BaseExtensions", "WCS.BaseExtensions\WCS.BaseExtensions.csproj", "{CDF091B2-2A9C-4A2A-BCB7-C1E7C1B62F79}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WCS.WorkEngineering", "WCS.WorkEngineering\WCS.WorkEngineering.csproj", "{87B00619-DA36-4469-B166-E7AAA9BB6123}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.WorkEngineering", "WCS.WorkEngineering\WCS.WorkEngineering.csproj", "{87B00619-DA36-4469-B166-E7AAA9BB6123}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -35,18 +25,6 @@ Global
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{5178BC6C-A3BF-4B36-A1C6-1B7DC5937474}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{5178BC6C-A3BF-4B36-A1C6-1B7DC5937474}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{5178BC6C-A3BF-4B36-A1C6-1B7DC5937474}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{5178BC6C-A3BF-4B36-A1C6-1B7DC5937474}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B0A743B0-881E-4997-BE75-B5C4ED4A9BE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B0A743B0-881E-4997-BE75-B5C4ED4A9BE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B0A743B0-881E-4997-BE75-B5C4ED4A9BE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B0A743B0-881E-4997-BE75-B5C4ED4A9BE4}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A93E66D2-2A49-410C-BDA6-AF0EF230A958}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A93E66D2-2A49-410C-BDA6-AF0EF230A958}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A93E66D2-2A49-410C-BDA6-AF0EF230A958}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A93E66D2-2A49-410C-BDA6-AF0EF230A958}.Release|Any CPU.Build.0 = Release|Any CPU
 		{E20F0C8A-619A-4D78-835C-909E81338458}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{E20F0C8A-619A-4D78-835C-909E81338458}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{E20F0C8A-619A-4D78-835C-909E81338458}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -63,18 +41,10 @@ Global
 		{54AF53DB-5A76-48D4-BD5F-F79D123DE1CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{54AF53DB-5A76-48D4-BD5F-F79D123DE1CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{54AF53DB-5A76-48D4-BD5F-F79D123DE1CB}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A8557AE8-BDBE-4508-AA58-C7E7F90EFDD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A8557AE8-BDBE-4508-AA58-C7E7F90EFDD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A8557AE8-BDBE-4508-AA58-C7E7F90EFDD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A8557AE8-BDBE-4508-AA58-C7E7F90EFDD2}.Release|Any CPU.Build.0 = Release|Any CPU
 		{6FE23C07-7FFC-4CF7-A889-9B62957E0BA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{6FE23C07-7FFC-4CF7-A889-9B62957E0BA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{6FE23C07-7FFC-4CF7-A889-9B62957E0BA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{6FE23C07-7FFC-4CF7-A889-9B62957E0BA5}.Release|Any CPU.Build.0 = Release|Any CPU
-		{CDF091B2-2A9C-4A2A-BCB7-C1E7C1B62F79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{CDF091B2-2A9C-4A2A-BCB7-C1E7C1B62F79}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{CDF091B2-2A9C-4A2A-BCB7-C1E7C1B62F79}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{CDF091B2-2A9C-4A2A-BCB7-C1E7C1B62F79}.Release|Any CPU.Build.0 = Release|Any CPU
 		{87B00619-DA36-4469-B166-E7AAA9BB6123}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{87B00619-DA36-4469-B166-E7AAA9BB6123}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{87B00619-DA36-4469-B166-E7AAA9BB6123}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -84,16 +54,11 @@ Global
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(NestedProjects) = preSolution
-		{5178BC6C-A3BF-4B36-A1C6-1B7DC5937474} = {43005E7B-7FC3-407D-B098-E58D0B5B465F}
-		{B0A743B0-881E-4997-BE75-B5C4ED4A9BE4} = {43005E7B-7FC3-407D-B098-E58D0B5B465F}
-		{A93E66D2-2A49-410C-BDA6-AF0EF230A958} = {43005E7B-7FC3-407D-B098-E58D0B5B465F}
 		{E20F0C8A-619A-4D78-835C-909E81338458} = {43005E7B-7FC3-407D-B098-E58D0B5B465F}
 		{17CF21B9-84AC-4FB3-9BC1-EF96CF8381CA} = {43005E7B-7FC3-407D-B098-E58D0B5B465F}
 		{300F18EA-128F-45EE-AE54-51AE8D2E0B57} = {9D01B749-E4C4-4AD4-82E1-5C3CA65295E5}
 		{54AF53DB-5A76-48D4-BD5F-F79D123DE1CB} = {9D01B749-E4C4-4AD4-82E1-5C3CA65295E5}
-		{A8557AE8-BDBE-4508-AA58-C7E7F90EFDD2} = {43005E7B-7FC3-407D-B098-E58D0B5B465F}
 		{6FE23C07-7FFC-4CF7-A889-9B62957E0BA5} = {9D01B749-E4C4-4AD4-82E1-5C3CA65295E5}
-		{CDF091B2-2A9C-4A2A-BCB7-C1E7C1B62F79} = {43005E7B-7FC3-407D-B098-E58D0B5B465F}
 		{87B00619-DA36-4469-B166-E7AAA9BB6123} = {9D01B749-E4C4-4AD4-82E1-5C3CA65295E5}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution

+ 123 - 0
WCS.Core/DbHelper/DB.cs

@@ -0,0 +1,123 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DbHelper
+{
+    /// <summary>
+    /// DB,禁止跨上下文使用
+    /// 1.异步情况: 在同一串await 中是一个上下文 (await 会改变线程和同步是不一样的)
+    /// 2.同步情况: 在同一个线程是同一个上下文
+    /// </summary>
+    public class Db
+    {
+        /// <summary>
+        /// 上下文集合
+        /// </summary>
+        private static List<ContextList> _contexts = new List<ContextList>();
+
+        /// <summary>
+        /// 默认上下文类类型
+        /// </summary>
+        public static string DefaultDbContextType { get; private set; } = null!;
+
+        public static T Do<T>(Func<Db, T> func)
+        {
+            var db = new Db();
+            try
+            {
+                db.Default.BeginTran();
+                var res = func(db);
+                db.Default.CommitTran();
+                return res;
+            }
+            catch (Exception ex)
+            {
+                //var qty = ex.EntityValidationErrors.Count();
+                //var info = ex.EntityValidationErrors.First();
+                //var msg = "有" + qty + "条数据验证失败,首条错误信息:\n" + string.Join("\n", info.MemberNames) + "\n" + (info.ErrorMessage ?? "");
+                Console.WriteLine(ex.Message);
+                throw new Exception(ex.Message);
+            }
+        }
+
+        public static void Do(Action<Db> act)
+        {
+            Do(db =>
+            {
+                act(db);
+                return 1;
+            });
+        }
+
+        /// <summary>
+        /// 设置默认链接
+        /// </summary>
+        /// <param name="key"></param>
+        public static void SetDefaultDbContextType(string key)
+        {
+            DefaultDbContextType = key;
+        }
+
+        /// <summary>
+        /// 默认链接
+        /// </summary>
+        public SqlSugarScope Default
+        {
+            get
+            {
+                if (DefaultDbContextType == null)
+                    throw new Exception("请先设置默认数据库,调用静态方法SetDefaultDbContextType()");
+                return Context(DefaultDbContextType);
+            }
+        }
+
+        /// <summary>
+        /// 创建一个上下文
+        /// </summary>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public static SqlSugarScope CreateContext(ConnectionConfig config, string key)
+        {
+            var ctx = _contexts.FirstOrDefault(v => v.Key == key);
+            if (ctx != null) return ctx.Client;
+            ctx = new ContextList(key, new SqlSugarScope(new ConnectionConfig()
+            {
+                ConnectionString = config.ConnectionString,
+                DbType = config.DbType,
+                IsAutoCloseConnection = true
+            }), config);
+
+            _contexts.Add(ctx);
+            return ctx.Client;
+        }
+
+        public SqlSugarScope Context(string key)
+        {
+            var ctx = _contexts.FirstOrDefault(v => v.Key == key);
+            if (ctx == null) throw new Exception("没有对应的链接,请先调用创建");
+            return ctx.Client;
+        }
+    }
+
+    /// <summary>
+    /// 链接
+    /// </summary>
+    public class ContextList
+
+    {
+        public ContextList(string key, SqlSugarScope client, ConnectionConfig connectionConfig)
+        {
+            this.Key = key;
+            Client = client;
+            ConnectionConfig = connectionConfig;
+        }
+
+        public string Key { get; set; }
+
+        public SqlSugarScope Client { get; set; }
+
+        public ConnectionConfig ConnectionConfig { get; set; }
+    }
+}

+ 54 - 0
WCS.Core/DbHelper/DbContext.cs

@@ -0,0 +1,54 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DbHelper
+{
+    public class DbContext
+    {
+        private static ConnectionConfig? _config = null;
+
+        public static void SetConfig(ConnectionConfig value)
+        {
+            _config = value;
+        }
+
+        /// <summary>
+        /// 用单例模式
+        /// </summary>
+        private static readonly SqlSugarScope SqlSugarScope = new SqlSugarScope(new ConnectionConfig()
+        {
+            ConnectionString = _config!.ConnectionString, //连接符字串
+            DbType = _config.DbType, //数据库类型
+            IsAutoCloseConnection = true //不设成true要手动close
+        }, db =>
+        {
+            //(A)全局生效配置点
+            //调试SQL事件,可以删掉
+            db.Aop.OnLogExecuting = (sql, pars) =>
+            {
+                DbLog.DBEX(sql);
+                //输出sql,查看执行sql
+                //5.0.8.2 获取无参数化 SQL
+                //UtilMethods.GetSqlString(DbType.SqlServer,sql,pars)
+            };
+        });
+
+        /// <summary>
+        /// 获取db链接
+        /// </summary>
+        /// <returns></returns>
+        /// <exception cref="Exception"></exception>
+        public static SqlSugarScope Db
+        {
+            get
+            {
+                if (_config == null) throw new Exception("请使用SetConfig方法写入数据库链接信息");
+                return SqlSugarScope;
+            }
+        }
+    }
+}

+ 57 - 0
WCS.Core/DbHelper/DbLog.cs

@@ -0,0 +1,57 @@
+using Log;
+using System.Collections.Generic;
+
+namespace DbHelper
+{
+    public class DbLog : ILogType
+    {
+        /// <summary>
+        /// 日志名称
+        /// </summary>
+        public string LogName => "Db";
+
+        /// <summary>
+        /// 日志
+        /// </summary>
+        public static ILogType Log { get; set; }
+
+        public Dictionary<string, string> SubLogNames { get; set; }
+
+        static DbLog()
+        {
+            Log = new DbLog();
+        }
+
+        public DbLog()
+        {
+            SubLogNames = new Dictionary<string, string>
+            {
+                ["DB"] = "Db"
+            };
+            LogHelper.Init(this);
+        }
+
+        /// <summary>
+        /// 用于记录DB执行内容
+        /// </summary>
+        /// <param name="msg"></param>
+        public static void DBEX(string msg)
+        {
+            Log.Info(msg, "DB_EX");
+        }
+
+        /// <summary>
+        /// 用于记录DB清理记录
+        /// </summary>
+        /// <param name="msg"></param>
+        public static void DB_CLEAN(string msg)
+        {
+            Log.Info(msg, "DB_CLEAN");
+        }
+
+        public static void INFO_PLCREADLOG(string msg)
+        {
+            Log.Info(msg, "INFO_PLCREADLOG");
+        }
+    }
+}

+ 109 - 0
WCS.Core/Redis/RedisHelper.cs

@@ -0,0 +1,109 @@
+using FreeRedis;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace WCS.Redis
+{
+    /// <summary>
+    /// Redis操作类
+    /// </summary>
+    public class RedisHelper
+    {
+        /// <summary>
+        /// 连接集合
+        /// </summary>
+        private static List<RedisClientList> RedisClients = new List<RedisClientList>();
+
+        /// <summary>
+        /// 默认上下文类类型
+        /// </summary>
+        public static string DefaultDbContextType { get; private set; } = null!;
+
+        /// <summary>
+        /// 设置默认链接
+        /// </summary>
+        /// <param name="key"></param>
+        public static void SetDefaultDbContextType(string key)
+        {
+            DefaultDbContextType = key;
+        }
+
+        /// <summary>
+        /// 默认链接
+        /// </summary>
+        public static RedisClient Default()
+        {
+            if (DefaultDbContextType == null)
+                throw new Exception("请先设置默认RedisDB库,调用静态方法SetDefaultDbContextType()");
+            return Context(DefaultDbContextType);
+        }
+
+        /// <summary>
+        /// 创建一个连接
+        /// </summary>
+        /// <param name="connectionString"> 连接字符串</param>
+        /// <param name="key">标识</param>
+        /// <param name="defaultClient"> 是否为默认连接,默认为false</param>
+        /// <returns></returns>
+        public static RedisClient CreateContext(string connectionString, string key, bool defaultClient = false)
+        {
+            var ctx = RedisClients.FirstOrDefault(v => v.Key == key);
+            if (ctx != null) return ctx.Client;
+            ctx = new RedisClientList(key, new RedisClient(connectionString), connectionString);
+            RedisClients.Add(ctx);
+            if (defaultClient)
+            {
+                SetDefaultDbContextType(key);
+            }
+            return ctx.Client;
+        }
+
+        /// <summary>
+        /// 获取指定的连接
+        /// </summary>
+        /// <param name="key"></param>
+        /// <returns></returns>
+        /// <exception cref="Exception"></exception>
+        public static RedisClient Context(string key)
+        {
+            var ctx = RedisClients.FirstOrDefault(v => v.Key == key);
+            if (ctx == null) throw new Exception("没有对应的链接,请先调用创建");
+            return ctx.Client;
+        }
+    }
+
+    /// <summary>
+    /// 链接集合
+    /// </summary>
+    public class RedisClientList
+    {
+        /// <summary>
+        /// 连接集合
+        /// </summary>
+        /// <param name="key">连接标识</param>
+        /// <param name="client">连接</param>
+        /// <param name="connectionConfig">连接字符串</param>
+        public RedisClientList(string key, RedisClient client, string connectionConfig)
+        {
+            this.Key = key;
+            Client = client;
+            ConnectionConfig = connectionConfig;
+        }
+
+        /// <summary>
+        /// 连接标识
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// 连接
+        /// </summary>
+        public RedisClient Client { get; set; }
+
+        /// <summary>
+        /// 连接字符串
+        /// </summary>
+        public string ConnectionConfig { get; set; }
+    }
+}

+ 179 - 0
WCS.Core/Virtual_PLC/PlcData.cs

@@ -0,0 +1,179 @@
+using FreeRedis;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System.Linq;
+using WCS.Redis;
+
+namespace WCS.Virtual_PLC
+{
+    /// <summary>
+    /// plc数据
+    /// </summary>
+    public class PlcData
+    {
+        private static string RedisKey = "Virtual_PLC";
+        private static RedisClient Redis;
+
+        /// <summary>
+        /// 数据结构缓存
+        /// </summary>
+        private static List<PLCData> PLCDatas { get; set; } = new List<PLCData>();
+
+        /// <summary>
+        /// redis 链接字符串
+        /// </summary>
+        /// <param name="redisClient">Redis链接字符串</param>
+        public PlcData(string redisClient)
+        {
+            Redis = RedisHelper.CreateContext(redisClient, RedisKey);
+        }
+
+        /// <summary>
+        /// redis 链接字符串
+        /// </summary>
+        /// <param name="redisClient"></param>
+        /// <returns></returns>
+        public static PlcData Init(string redisClient)
+        {
+            return new PlcData(redisClient);
+        }
+
+        /// <summary>
+        /// 初始化PLC数据
+        /// </summary>
+        /// <param name="pLCData">一个PLC</param>
+        private void InitPlcData(PLCData pLCData)
+        {
+            if (!PLCDatas.Contains(pLCData))
+            {
+                PLCDatas.Add(pLCData);
+            }
+            //用总长度除以数据长度,再以每断数据的起始位置、IP、DB组成Key
+            var mun = pLCData.Length / pLCData.DataLength;
+            int addstart = 0;
+
+            for (int i = 0; i < mun; i++)
+            {
+                var key = $"{pLCData.IP}:{pLCData.DB}:{addstart}";
+                if (Redis.Exists(key)) continue;
+                Redis.Set(key, new byte[pLCData.DataLength]);
+                addstart = addstart + pLCData.DataLength;
+            }
+        }
+
+        /// <summary>
+        /// 初始化PLC数据
+        /// </summary>
+        /// <param name="pLCDatas">多个PLC</param>
+        public void InitPlcData(List<PLCData> pLCDatas)
+        {
+            string key = "PLCDataList";
+            if (Redis.Exists(key))
+            {
+                //判断值是否相等,值相等代表已经有过数据生成了,并且没有任何变化
+                var RedisPlcData = Redis.Get(key);
+                if (JsonConvert.SerializeObject(pLCDatas) == RedisPlcData)
+                {
+                    PLCDatas = pLCDatas;
+                    return;
+                }
+            }
+
+            pLCDatas.ForEach(v =>
+            {
+                InitPlcData(v);
+            });
+            Redis.Set(key, JsonConvert.SerializeObject(pLCDatas));
+        }
+
+        /// <summary>
+        /// 按照DB读取
+        /// </summary>
+        /// <param name="pLCData"></param>
+        /// <returns></returns>
+        public static byte[] Read(PLCData pLCData)
+        {
+            byte[] data = new byte[pLCData.Length];
+            //用总长度除以数据长度,再以每断数据的起始位置、IP、DB组成Key
+            var mun = pLCData.Length / pLCData.DataLength;
+            int addstart = 0;
+
+            for (int i = 0; i < mun; i++)
+            {
+                var a = Redis.Get<byte[]>($"{pLCData.IP}:{pLCData.DB}:{addstart}");
+                a.CopyTo(data, addstart);
+                addstart = addstart + pLCData.DataLength;
+            }
+            return data;
+        }
+
+        /// <summary>
+        /// 按照长度读取
+        /// </summary>
+        /// <param name="pLCData"></param>
+        /// <param name="startLength">起始长度</param>
+        /// <returns></returns>
+        public static byte[] Read(PLCData pLCData, int startLength)
+        {
+            return System.Text.Encoding.Default.GetBytes(Redis.Get($"{pLCData.IP}:{pLCData.DB}:{startLength}"));
+        }
+
+        /// <summary>
+        /// 写入数据
+        /// </summary>
+        /// <param name="pLCData"></param>
+        /// <param name="startLength"></param>
+        /// <param name="value"></param>
+        public static void Write(PLCData pLCData, int startLength, byte[] value)
+        {
+            var data = PLCDatas.Find(v => v.IP == pLCData.IP && v.DB == pLCData.DB);
+            int start = 0;
+            if (data.DataLength == data.Length) //数据长度与总长度相等时计算
+            {
+                start = startLength < data.DataLength ? 0 : (data.DataLength - startLength) + startLength;
+            }
+            else //不等
+            {
+                int addstart = 0;
+                var mun = data.Length / data.DataLength;
+                var a = new List<int>();
+                for (int i = 0; i < mun; i++)
+                {
+                    a.Add(addstart);
+                    addstart = addstart + data.DataLength;
+                }
+                start = a.Where(v => v <= startLength).OrderByDescending(v => v).FirstOrDefault();
+                startLength = startLength - start;
+            }
+            var bytes = System.Text.Encoding.Default.GetBytes(Redis.Get($"{pLCData.IP}:{pLCData.DB}:{start}")); //获取原有数据
+            value.CopyTo(bytes, startLength); //将变更的数据,更新到redis字节组中
+            Redis.Set($"{pLCData.IP}:{pLCData.DB}:{start}", bytes);
+        }
+    }
+
+    /// <summary>
+    /// PLC数据结构
+    /// </summary>
+    public class PLCData
+    {
+        /// <summary>
+        /// IP
+        /// </summary>
+        public string IP { get; set; }
+
+        /// <summary>
+        /// DB
+        /// </summary>
+        public int DB { get; set; }
+
+        /// <summary>
+        /// 总长度
+        /// </summary>
+        public int Length { get; set; }
+
+        /// <summary>
+        /// 数据长度
+        /// </summary>
+        public int DataLength { get; set; }
+    }
+}