From 43694e3185e23cc24d68a5bb03eb229d21995c2e Mon Sep 17 00:00:00 2001 From: hehaibing-1996 Date: Fri, 6 Dec 2024 11:12:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=95=E7=81=AF=EF=BC=9A=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=AE=A2=E6=88=B7=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WCS.BLL/DbModels/ShelfInfo.cs | 9 +- WCS.BLL/Manager/DbInit.cs | 2 + WCS.BLL/Manager/TCPClientManager.cs | 321 +++++++++++------- .../Services/Service/SingleLightService.cs | 118 +++++-- 4 files changed, 290 insertions(+), 160 deletions(-) diff --git a/WCS.BLL/DbModels/ShelfInfo.cs b/WCS.BLL/DbModels/ShelfInfo.cs index 9753562..28e4dee 100644 --- a/WCS.BLL/DbModels/ShelfInfo.cs +++ b/WCS.BLL/DbModels/ShelfInfo.cs @@ -90,13 +90,18 @@ namespace WCS.DAL.DbModels [SugarColumn(ColumnName = "group_name", Length = 50, IsNullable = false, ColumnDescription = "货架的组别、区域(区分单个软件管哪些货架的,前端的配置文件配置一个组别,查询时只显示当前组别的货架)")] public string GroupName { get; set; } - /// - /// 是否串联绑定 + /// 模块是不是 /// [SugarColumn(ColumnName = "is_bind", IsNullable = false, ColumnDescription = "是否串联绑定")] public bool IsBind { get; set; } + /// + /// 货架的模块是不是服务端 + /// + [SugarColumn(ColumnName = "is_service", IsNullable = true, ColumnDescription = "货架的模块是不是服务端")] + public bool IsService { get; set; } = false; + /// /// 串联绑定后的大货架编码 /// diff --git a/WCS.BLL/Manager/DbInit.cs b/WCS.BLL/Manager/DbInit.cs index 065e18b..906dd51 100644 --- a/WCS.BLL/Manager/DbInit.cs +++ b/WCS.BLL/Manager/DbInit.cs @@ -78,6 +78,8 @@ namespace WCS.BLL.Manager , typeof(AppVersion) ); + //DbHelp.db.CodeFirst.InitTables(typeof(ShelfInfo)); + Logs.Write("【初始化数据库】db(业务数据库)建表", LogsType.StartBoot); DbHelp.dbLog.CodeFirst.InitTables(typeof(SystemApiLogRecord)); Logs.Write("【初始化数据库】dblog(日志数据库)建表", LogsType.StartBoot); diff --git a/WCS.BLL/Manager/TCPClientManager.cs b/WCS.BLL/Manager/TCPClientManager.cs index 8a6a228..1a3a39f 100644 --- a/WCS.BLL/Manager/TCPClientManager.cs +++ b/WCS.BLL/Manager/TCPClientManager.cs @@ -23,12 +23,15 @@ namespace WCS.BLL.Manager /// public static List TCPClients = new List(); + public static TcpService Service { get; set; } + public static void InitTcpClient() { + #region 模块是Service的逻辑 Logs.Write("【InitTcpClient】开始", LogsType.StartBoot); - - var clientsInDB = DbHelp.db.Queryable() + var moduleServices = DbHelp.db.Queryable() .WhereIF(!string.IsNullOrEmpty(LocalFile.Config.GroupName), t => t.GroupName == LocalFile.Config.GroupName) + .Where(t => t.IsService) .Select(t => new { IP = t.ClientIp, @@ -37,154 +40,208 @@ namespace WCS.BLL.Manager }) .Distinct() .ToList(); - Logs.Write($"【InitTcpClient】需要连接的服务端地址如下:\r\n{string.Join(";", clientsInDB)}", LogsType.StartBoot); - foreach (var cleientInDB in clientsInDB) + if (moduleServices != null && moduleServices.Count > 0) { + Logs.Write($"【InitTcpClient】需要连接的服务端地址如下:\r\n{string.Join(";", moduleServices)}", LogsType.StartBoot); + foreach (var cleientInDB in moduleServices) + { + Task.Run(() => + { + var tcpCleint = new TCPClient(cleientInDB.IP, cleientInDB.Port, cleientInDB.ShelfTypeName); + tcpCleint.tcpClient.Received += (client, e) => + { + var clientIpHost = client.IP + ":" + client.Port; + var TcpCleint = TCPClientManager.GetTCPClientByIPHost(clientIpHost); + if (TcpCleint == null) + { + return EasyTask.CompletedTask; + } + + var data = e.ByteBlock.Buffer.Take((int)e.ByteBlock.Length).ToArray(); + + + Logs.Write($"【接收{clientIpHost}】{BitConverter.ToString(data)}", LogsType.Instructions); + + e.ByteBlock.Clear(); + var len = data.Length; + + if (tcpCleint.ShelfTypeName == "信息化货架") + { + Logs.Write($"【信息化货架开始处理接收数据】{BitConverter.ToString(data)}", LogsType.InstructionsProcess); + Helper.ReturnDataProcess(TcpCleint, data); + Logs.Write($"【信息化货架完成处理接收数据】{BitConverter.ToString(data)}", LogsType.InstructionsProcess); + return EasyTask.CompletedTask; + } + + if (tcpCleint.ShelfTypeName == "液晶货架") + { + Logs.Write($"【液晶货架开始处理接收数据】{BitConverter.ToString(data)}", LogsType.InstructionsProcess); + //Helper.ReturnDataProcess(TcpCleint, data); + Logs.Write($"【液晶货架完成处理接收数据】{BitConverter.ToString(data)}", LogsType.InstructionsProcess); + return EasyTask.CompletedTask; + } + + for (int index = 0; index < data.Length - TcpCleint.PreFixLength; index++) + { + //协议拆包 通过前缀校验是否为完整数据包 + var prefixInData = data.Skip(index).Take(TcpCleint.PreFixLength); + var isEqual = prefixInData.SequenceEqual(TcpCleint.Prefix); + if (isEqual) + { + var dataTemp = data.Skip(index).Take(TcpCleint.PreFixLength + TcpCleint.DataLength).ToArray(); + if (dataTemp.Length < TcpCleint.PreFixLength + TcpCleint.DataLength)//拆包后不满足一条指令的长度 + { + continue; + } + Logs.Write($"【处理单条指令 开始】{BitConverter.ToString(dataTemp)}", LogsType.InstructionsProcess); + index += (TcpCleint.PreFixLength + TcpCleint.DataLength - 1);//每次循环index会+1 所以这里-1 + //获取板子ID + var boardId = (dataTemp[TcpCleint.PreFixLength + 0] << 8) + dataTemp[TcpCleint.PreFixLength + 1]; + var lightNumber = Convert.ToInt32(dataTemp[TcpCleint.PreFixLength + 3]); + //报警灯 返回来就修改对应的灯的颜色 + if (dataTemp[TcpCleint.PreFixLength + 2] == 0x20) + { + var shelf = ShelfManager.Shelves.Where(t => t.ClientIp == clientIpHost) + .Where(t => t.LightId == boardId) + .FirstOrDefault(); + var smartShelf = shelf as SmartShelf; + smartShelf?.WarningLightProcess(dataTemp, boardId, lightNumber); + } + //!= 0x20 货架类型协议返回 + else + { + var shelf = ShelfManager.Shelves + .Where(t => t.ClientIp == clientIpHost) + .Where(t => t.ModuleIds != null && t.ModuleIds.Contains(boardId)) + .FirstOrDefault(); + var smartShelf = shelf as SmartShelf; + smartShelf?.ProtocolProcess(dataTemp, boardId, lightNumber); + } + Logs.Write($"【处理单条指令 结束】{BitConverter.ToString(dataTemp)}", LogsType.InstructionsProcess); + } + } + return EasyTask.CompletedTask; + }; + //配置首次连接后复位操作 + tcpCleint.tcpClient.Connected += (client, e) => + { + Logs.Write($"【TcpClient】{client.IP}完成连接,端口号{client.Port}", LogsType.StartBoot); + var clientIpHost = client.IP + ":" + client.Port; + var TcpCleint = TCPClientManager.GetTCPClientByIPHost(clientIpHost); + if (TcpCleint == null) + { + return EasyTask.CompletedTask; + } + //首次连接 + if (TcpCleint.IsFirstConnected == false) + { + Logs.Write($"【InitTcpClient】{clientIpHost}完成首次连接", LogsType.StartBoot); + + + + Console.WriteLine($"【InitTcpClient】{clientIpHost}完成首次连接"); + InitStatus(TcpCleint); + TcpCleint.IsFirstConnected = true; + //获取剩余未完成连接的tcp + var noFirstConnectedTcps = TCPClientManager.TCPClients.Where(t => t.IsFirstConnected == false) + .Select(t => t.RemoteIPHost) + .ToList(); + Logs.Write($"【InitTcpClient】剩余未完成连接的TCP为{string.Join(";", noFirstConnectedTcps)}", LogsType.StartBoot); + } + return EasyTask.CompletedTask; + }; + + lock (TCPClients)//避免添加失败的情况 + { + TCPClients.Add(tcpCleint); + } + + tcpCleint.Connect(); + }); + } + + //启动线程监听所有TCP是否已经完成首次连接 Task.Run(() => { - var tcpCleint = new TCPClient(cleientInDB.IP, cleientInDB.Port, cleientInDB.ShelfTypeName); - tcpCleint.tcpClient.Received += (client, e) => + while (true) { - var clientIpHost = client.IP + ":" + client.Port; - var TcpCleint = TCPClientManager.GetTCPClientByIPHost(clientIpHost); - if (TcpCleint == null) + try { - return EasyTask.CompletedTask; - } - - var data = e.ByteBlock.Buffer.Take((int)e.ByteBlock.Length).ToArray(); - - - Logs.Write($"【接收{clientIpHost}】{BitConverter.ToString(data)}", LogsType.Instructions); - - e.ByteBlock.Clear(); - var len = data.Length; - - if (tcpCleint.ShelfTypeName == "信息化货架") - { - Logs.Write($"【信息化货架开始处理接收数据】{BitConverter.ToString(data)}", LogsType.InstructionsProcess); - Helper.ReturnDataProcess(TcpCleint, data); - Logs.Write($"【信息化货架完成处理接收数据】{BitConverter.ToString(data)}", LogsType.InstructionsProcess); - return EasyTask.CompletedTask; - } - - if (tcpCleint.ShelfTypeName == "液晶货架") - { - Logs.Write($"【液晶货架开始处理接收数据】{BitConverter.ToString(data)}", LogsType.InstructionsProcess); - //Helper.ReturnDataProcess(TcpCleint, data); - Logs.Write($"【液晶货架完成处理接收数据】{BitConverter.ToString(data)}", LogsType.InstructionsProcess); - return EasyTask.CompletedTask; - } - - for (int index = 0; index < data.Length - TcpCleint.PreFixLength; index++) - { - //协议拆包 通过前缀校验是否为完整数据包 - var prefixInData = data.Skip(index).Take(TcpCleint.PreFixLength); - var isEqual = prefixInData.SequenceEqual(TcpCleint.Prefix); - if (isEqual) + Thread.Sleep(1000); + var noFirstConnectedClients = TCPClientManager.TCPClients.Where(t => t.IsFirstConnected == false) + .ToList(); + if (noFirstConnectedClients.Count == 0) { - var dataTemp = data.Skip(index).Take(TcpCleint.PreFixLength + TcpCleint.DataLength).ToArray(); - if (dataTemp.Length < TcpCleint.PreFixLength + TcpCleint.DataLength)//拆包后不满足一条指令的长度 + break; + } + else + { + Console.WriteLine($"存在tcp未完成首次连接,继续重连!"); + noFirstConnectedClients.ForEach(t => { - continue; - } - Logs.Write($"【处理单条指令 开始】{BitConverter.ToString(dataTemp)}", LogsType.InstructionsProcess); - index += (TcpCleint.PreFixLength + TcpCleint.DataLength - 1);//每次循环index会+1 所以这里-1 - //获取板子ID - var boardId = (dataTemp[TcpCleint.PreFixLength + 0] << 8) + dataTemp[TcpCleint.PreFixLength + 1]; - var lightNumber = Convert.ToInt32(dataTemp[TcpCleint.PreFixLength + 3]); - //报警灯 返回来就修改对应的灯的颜色 - if (dataTemp[TcpCleint.PreFixLength + 2] == 0x20) - { - var shelf = ShelfManager.Shelves.Where(t => t.ClientIp == clientIpHost) - .Where(t => t.LightId == boardId) - .FirstOrDefault(); - var smartShelf = shelf as SmartShelf; - smartShelf?.WarningLightProcess(dataTemp, boardId, lightNumber); - } - //!= 0x20 货架类型协议返回 - else - { - var shelf = ShelfManager.Shelves - .Where(t => t.ClientIp == clientIpHost) - .Where(t => t.ModuleIds != null && t.ModuleIds.Contains(boardId)) - .FirstOrDefault(); - var smartShelf = shelf as SmartShelf; - smartShelf?.ProtocolProcess(dataTemp, boardId, lightNumber); - } - Logs.Write($"【处理单条指令 结束】{BitConverter.ToString(dataTemp)}", LogsType.InstructionsProcess); + t.ReConnectAsync(); + }); } } - return EasyTask.CompletedTask; - }; - //配置首次连接后复位操作 - tcpCleint.tcpClient.Connected += (client, e) => - { - Logs.Write($"【TcpClient】{client.IP}完成连接,端口号{client.Port}", LogsType.StartBoot); - var clientIpHost = client.IP + ":" + client.Port; - var TcpCleint = TCPClientManager.GetTCPClientByIPHost(clientIpHost); - if (TcpCleint == null) + catch (Exception ex) { - return EasyTask.CompletedTask; + } - //首次连接 - if (TcpCleint.IsFirstConnected == false) - { - Logs.Write($"【InitTcpClient】{clientIpHost}完成首次连接", LogsType.StartBoot); - - - - Console.WriteLine($"【InitTcpClient】{clientIpHost}完成首次连接"); - InitStatus(TcpCleint); - TcpCleint.IsFirstConnected = true; - //获取剩余未完成连接的tcp - var noFirstConnectedTcps = TCPClientManager.TCPClients.Where(t => t.IsFirstConnected == false) - .Select(t => t.RemoteIPHost) - .ToList(); - Logs.Write($"【InitTcpClient】剩余未完成连接的TCP为{string.Join(";", noFirstConnectedTcps)}", LogsType.StartBoot); - } - return EasyTask.CompletedTask; - }; - - lock (TCPClients)//避免添加失败的情况 - { - TCPClients.Add(tcpCleint); } - - tcpCleint.Connect(); }); + Logs.Write("【InitTcpClient】完成 后台继续连接", LogsType.StartBoot); } + #endregion - //启动线程监听所有TCP是否已经完成首次连接 - Task.Run(() => + #region 模块是Client的逻辑 + var moduleClients = DbHelp.db.Queryable() + .WhereIF(!string.IsNullOrEmpty(LocalFile.Config.GroupName), t => t.GroupName == LocalFile.Config.GroupName) + .Where(t => t.IsService == false) + .Select(t => new + { + IP = t.ClientIp, + ShelfTypeName = t.ShelfTypeName, + Port = t.Port, + }) + .Distinct() + .ToList(); + //有客户端作客户端时才需要初始化一个服务端 + if (moduleClients != null && moduleClients.Count > 0) { - while (true) + Service = new TcpService(); + Service.Connecting = (client, e) => { - try - { - Thread.Sleep(1000); - var noFirstConnectedClients = TCPClientManager.TCPClients.Where(t => t.IsFirstConnected == false) - .ToList(); - if (noFirstConnectedClients.Count == 0) - { - break; - } - else - { - Console.WriteLine($"存在tcp未完成首次连接,继续重连!"); - noFirstConnectedClients.ForEach(t => - { - t.ReConnectAsync(); - }); - } - } - catch (Exception ex) - { + return EasyTask.CompletedTask; + };//有客户端正在连接 + Service.Connected = (client, e) => { return EasyTask.CompletedTask; };//有客户端成功连接 + Service.Disconnecting = (client, e) => { return EasyTask.CompletedTask; };//有客户端正在断开连接,只有当主动断开时才有效。 + Service.Disconnected = (client, e) => { return EasyTask.CompletedTask; };//有客户端断开连接 + Service.Received = (client, e) => + { + //从客户端收到信息 + var mes = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 0, e.ByteBlock.Len);//注意:数据长度是byteBlock.Len + client.Logger.Info($"已从{client.Id}接收到信息:{mes}"); - } - } - }); - Logs.Write("【InitTcpClient】完成 后台继续连接", LogsType.StartBoot); + //client.Send(mes);//将收到的信息直接返回给发送方 + + + return EasyTask.CompletedTask; + }; + + Service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts("tcp://0.0.0.0:9999", 7790)//同时监听两个地址 + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) + }) + .ConfigurePlugins(a => + { + //a.Add();//此处可以添加插件 + })); + + Service.Start(); + } + #endregion } //后台启动时给所有板子、警示灯发送复位操作 保持状态一致 diff --git a/WCS.BLL/Services/Service/SingleLightService.cs b/WCS.BLL/Services/Service/SingleLightService.cs index 415d166..9b6d7f0 100644 --- a/WCS.BLL/Services/Service/SingleLightService.cs +++ b/WCS.BLL/Services/Service/SingleLightService.cs @@ -75,7 +75,7 @@ namespace WCS.BLL.Services.Service { var shelfModel = new SingleLightShelfModel(); //报警灯 - if(shelf.LightId > 0) + if (shelf.LightId > 0) { shelfModel.WarningLightMode = request.LightMode; } @@ -96,29 +96,62 @@ namespace WCS.BLL.Services.Service } //合并:同一个TCP的货架合并 报警灯和库位灯统一只发送一条指令 - var clientIpList = shelfs.Select(t => t.ClientIp) - .Distinct() - .ToList(); - foreach (var clientIp in clientIpList) + var clients = shelfs.Select(t => new { - var shelfModelsInOneIp = shelfModels.Where(t => t.ClientIp == clientIp).ToList(); + ClientIp = t.ClientIp, + IsService = t.IsService, + }) + .Distinct() + .ToList(); + foreach (var client in clients) + { + var shelfModelsInOneIp = shelfModels.Where(t => t.ClientIp == client.ClientIp).ToList(); + var sendData = Helper.SingleLightControl(shelfModelsInOneIp); - TCPClient tcpClient = TCPClientManager.GetTCPClientByIPHost(clientIp); - if (tcpClient != null) + if (client.IsService) { - try + TCPClient tcpClient = TCPClientManager.GetTCPClientByIPHost(client.ClientIp); + if (tcpClient != null) { - tcpClient.Send(sendData); - Logs.Write("【单灯单独控制】发送指令" + BitConverter.ToString(sendData)); + try + { + tcpClient.Send(sendData); + Logs.Write("【单灯单独控制】发送指令" + BitConverter.ToString(sendData)); + } + catch (Exception ex) + { + Logs.Write($"【单灯单独控制】{client}以下指令发送中遇到异常{ex.Message}" + BitConverter.ToString(sendData)); + } } - catch (Exception ex) + else { - Logs.Write($"【单灯单独控制】{clientIp}以下指令发送中遇到异常{ex.Message}" + BitConverter.ToString(sendData)); + Logs.Write($"【单灯单独控制】{client}未连接,以下指令未能成功发送" + BitConverter.ToString(sendData)); } } else { - Logs.Write($"【单灯单独控制】{clientIp}未连接,以下指令未能成功发送" + BitConverter.ToString(sendData)); + var tcpClient = TCPClientManager.Service.GetClients().Where(t => t.IP + ":" + t.Port.ToString() == client.ClientIp).FirstOrDefault(); + if (tcpClient != null) + { + try + { + tcpClient.Send(sendData,0,sendData.Length); + Logs.Write("【单灯单独控制】发送指令" + BitConverter.ToString(sendData)); + } + catch (Exception ex) + { + Logs.Write($"【单灯单独控制】{client}以下指令发送中遇到异常{ex.Message}" + BitConverter.ToString(sendData)); + } + } + else + { + Logs.Write($"【单灯单独控制】{client}未连接,以下指令未能成功发送" + BitConverter.ToString(sendData)); + return new ResponseCommon() + { + Code = 201, + Message = $"【单灯单独控制】{client}未连接,以下指令未能成功发送", + }; + } } } @@ -172,31 +205,64 @@ namespace WCS.BLL.Services.Service var shelfs = DbHelp.db.Queryable().Where(t => shelfIds.Contains(t.Id)) .ToList(); //获取对应货架所有IP - var clientIPs = shelfs.Select(t => t.ClientIp) - .Distinct() - .ToList(); + var clients = shelfs.Select(t => new + { + ClientIp = t.ClientIp, + IsService = t.IsService, + }) + .Distinct() + .ToList(); //挨个发关灯指令 - foreach (var clientIP in clientIPs) + foreach (var client in clients) { //生成关灯指令 var sendData = Helper.SingleLightTrunOffAllLight(); - TCPClient tcpClient = TCPClientManager.GetTCPClientByIPHost(clientIP); - if (tcpClient != null) + + if (client.IsService) { - try + TCPClient tcpClient = TCPClientManager.GetTCPClientByIPHost(client.ClientIp); + if (tcpClient != null) { - tcpClient.Send(sendData); - Logs.Write("【单灯单独控制】发送指令" + BitConverter.ToString(sendData)); + try + { + tcpClient.Send(sendData); + Logs.Write("【熄灯】发送指令" + BitConverter.ToString(sendData)); + } + catch (Exception ex) + { + Logs.Write($"【熄灯】{client}以下指令发送中遇到异常{ex.Message}" + BitConverter.ToString(sendData)); + } } - catch (Exception ex) + else { - Logs.Write($"【单灯单独控制】{clientIP}以下指令发送中遇到异常{ex.Message}" + BitConverter.ToString(sendData)); + Logs.Write($"【熄灯】{client}未连接,以下指令未能成功发送" + BitConverter.ToString(sendData)); } } else { - Logs.Write($"【单灯单独控制】{clientIP}未连接,以下指令未能成功发送" + BitConverter.ToString(sendData)); + var tcpClient = TCPClientManager.Service.GetClients().Where(t => t.IP + ":" + t.Port.ToString() == client.ClientIp).FirstOrDefault(); + if (tcpClient != null) + { + try + { + tcpClient.Send(sendData, 0, sendData.Length); + Logs.Write("【熄灯】发送指令" + BitConverter.ToString(sendData)); + } + catch (Exception ex) + { + Logs.Write($"【熄灯】{client}以下指令发送中遇到异常{ex.Message}" + BitConverter.ToString(sendData)); + } + } + else + { + Logs.Write($"【熄灯】{client}未连接,以下指令未能成功发送" + BitConverter.ToString(sendData)); + return new ResponseCommon() + { + Code = 201, + Message = $"【熄灯】{client}未连接,以下指令未能成功发送", + }; + } } }