299 lines
14 KiB
C#
299 lines
14 KiB
C#
using SqlSugar;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Net.Sockets;
|
||
using System.Security.Cryptography.X509Certificates;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using TouchSocket.Core;
|
||
using TouchSocket.Sockets;
|
||
using WCS.BLL.Config;
|
||
using WCS.BLL.HardWare;
|
||
using WCS.BLL.Tool;
|
||
using WCS.DAL.Db;
|
||
using WCS.DAL.DbModels;
|
||
|
||
namespace WCS.BLL.Manager
|
||
{
|
||
public static class TCPClientManager
|
||
{
|
||
/// <summary>
|
||
/// 货架类型的TCP连接管理
|
||
/// </summary>
|
||
public static List<TCPClient> TCPClients = new List<TCPClient>();
|
||
|
||
public static TcpService Service { get; set; }
|
||
|
||
public static void InitTcpClient()
|
||
{
|
||
#region 模块是Service的逻辑
|
||
Logs.Write("【InitTcpClient】开始", LogsType.StartBoot);
|
||
var moduleServices = DbHelp.db.Queryable<ShelfInfo>()
|
||
.WhereIF(!string.IsNullOrEmpty(LocalFile.Config.GroupName), t => t.GroupName == LocalFile.Config.GroupName)
|
||
.Where(t => t.IsService)
|
||
.Select(t => new
|
||
{
|
||
IP = t.ClientIp,
|
||
ShelfTypeName = t.ShelfTypeName,
|
||
Port = t.Port,
|
||
})
|
||
.Distinct()
|
||
.ToList();
|
||
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.tcpReceiveClient.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 == "液晶标签货架")
|
||
{
|
||
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会+1 所以这里-1
|
||
index += (TcpCleint.PreFixLength + TcpCleint.DataLength - 1);
|
||
//获取板子ID
|
||
var boardId = (dataTemp[TcpCleint.PreFixLength + 0] << 8) + dataTemp[TcpCleint.PreFixLength + 1];
|
||
//报警灯 返回来就修改对应的灯的颜色
|
||
if (dataTemp[TcpCleint.PreFixLength + 2] == 0x20)
|
||
{
|
||
var shelf = ShelfManager.Shelves.Where(t => t.ClientIp == clientIpHost)
|
||
.Where(t => t.LightId == boardId)
|
||
.FirstOrDefault();
|
||
var mxl4Shelf = shelf as MXL4Shelf;
|
||
mxl4Shelf?.WarningLightProcess(dataTemp, boardId);
|
||
}
|
||
//!= 0x20 货架类型协议返回
|
||
else
|
||
{
|
||
var shelf = ShelfManager.Shelves
|
||
.Where(t => t.ClientIp == clientIpHost)
|
||
.Where(t => t.ModuleIds != null && t.ModuleIds.Contains(boardId))
|
||
.FirstOrDefault();
|
||
var mxl4Shelf = shelf as MXL4Shelf;
|
||
mxl4Shelf?.ProtocolProcess(dataTemp, boardId);
|
||
}
|
||
Logs.Write($"【处理单条指令 结束】{BitConverter.ToString(dataTemp)}", LogsType.InstructionsProcess);
|
||
}
|
||
}
|
||
}
|
||
return EasyTask.CompletedTask;
|
||
};
|
||
//配置首次连接后复位操作
|
||
tcpCleint.tcpSendClient.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(() =>
|
||
{
|
||
while (true)
|
||
{
|
||
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)
|
||
{
|
||
|
||
}
|
||
}
|
||
});
|
||
Logs.Write("【InitTcpClient】完成 后台继续连接", LogsType.StartBoot);
|
||
}
|
||
#endregion
|
||
|
||
#region 模块是Client的逻辑
|
||
var moduleClients = DbHelp.db.Queryable<ShelfInfo>()
|
||
.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)
|
||
{
|
||
Service = new TcpService();
|
||
Service.Connecting = (client, e) =>
|
||
{
|
||
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}");
|
||
|
||
//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
|
||
}
|
||
|
||
//后台启动时给所有板子、警示灯发送复位操作 保持状态一致
|
||
public static void InitStatus()
|
||
{
|
||
Task.Run(() =>
|
||
{
|
||
try
|
||
{
|
||
Thread.Sleep(1000);
|
||
//给所有板子发复位
|
||
TCPClients.ForEach(tcpClient =>
|
||
{
|
||
//板子复位
|
||
new SmartShelfModule()
|
||
{
|
||
BoardId = 2047
|
||
}.Reset(tcpClient);
|
||
//报警灯复位
|
||
new WarningLight().CloseLight(tcpClient);
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logs.Write($"启动时复位异常,{ex.Message}");
|
||
}
|
||
});
|
||
}
|
||
|
||
//后台启动时给所有板子、警示灯发送复位操作 保持状态一致
|
||
public static void InitStatus(TCPClient tcpClient)
|
||
{
|
||
var shelfInfo = DbHelp.db.Queryable<ShelfInfo>().Where(t => t.ClientIp == tcpClient.RemoteIPHost).ToList();
|
||
if (shelfInfo.Count != 0)
|
||
{
|
||
if (shelfInfo[0].ShelfTypeName == "信息化货架")
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
Task.Run(() =>
|
||
{
|
||
try
|
||
{
|
||
Thread.Sleep(1000);
|
||
|
||
//板子复位
|
||
new SmartShelfModule()
|
||
{
|
||
BoardId = 2047
|
||
}.Reset(tcpClient);
|
||
//报警灯复位
|
||
new WarningLight().CloseLight(tcpClient);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logs.Write($"[{tcpClient.RemoteIPHost}]:启动时复位异常,{ex.Message}");
|
||
}
|
||
});
|
||
}
|
||
public static TCPClient GetTCPClientByIPHost(string IpHost)
|
||
{
|
||
return TCPClients.Where(t => t.RemoteIPHost == IpHost).FirstOrDefault();
|
||
}
|
||
}
|
||
}
|