using Ems.CollectService.Analysis; using Ems.CollectService.Common; using Ems.CollectService.Entity; using Ems.CollectService.Redis; using Ems.CollectService.SqlSugarCore; using NetTaste; using NLog; using SqlSugar; using StackExchange.Redis; using System; using System.Net; using System.Text; using System.Threading.Tasks; using TouchSocket.Core; using TouchSocket.Sockets; namespace Ems.CollectService.TouchSocket { public sealed class TcpServer { private static readonly Lazy lazy = new Lazy(() => new TcpServer()); private Logger logger = LogManager.GetCurrentClassLogger(); private TcpService service = new TcpService(); private StringChange stringChange = StringChange.Instance; private BufferAnalysis bufferAnalysis = BufferAnalysis.Instance; private MsgUtil msgUtil = MsgUtil.Instance; private JsonChange jsonChange = JsonChange.Instance; //private SqlSugarClient baseService = SqlGenerator.GetMySqlInstance(); //private ConnectionMultiplexer conn = RedisHelper.RedisConn; public static TcpServer Instance { get { return lazy.Value; } } private TcpServer() { } public void Init(int serverPort) { try { service.Connecting = (client, e) => { //有客户端正在连接 logger.Info($"客户端{client.IP}正在接入服务"); }; service.Connected = (client, e) => { //有客户端成功连接 logger.Trace($"客户端{client.IP}接入服务成功,Id:{client.ID}"); }; service.Disconnected = (client, e) => { //有客户端断开连接 logger.Trace($"客户端{client.IP}断开连接,Id:{client.ID}"); if (client.ID.Length >= 4) { string clientId = string.Format("E{0}", client.ID.ToString().Substring(2, client.ID.ToString().Length - 2)); bufferAnalysis.UpdateCollectDeviceOnLineState(clientId, 0); } }; service.Received = (client, byteBlock, requestInfo) => { if (requestInfo is MyFixedHeaderRequestInfo myRequestInfo) { string body = Encoding.UTF8.GetString(myRequestInfo.Body, 0, myRequestInfo.Body.Length); bufferMemory(client, myRequestInfo,service); } }; service.Setup(new TouchSocketConfig()//载入配置 .SetListenIPHosts(new IPHost[] { new IPHost($"0.0.0.0:{serverPort}") })//同时监听两个地址 .SetDataHandlingAdapter(() => { return new MyFixedHeaderCustomDataHandlingAdapter(); })//配置适配器 .ConfigureContainer(a =>//容器的配置顺序应该在最前面 { a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) }) .ConfigurePlugins(a => { //a.Add().SetDuration(new TimeSpan(0, 0, 0, 5, 0)); })) .Start();//启动 ReadMeterTask(); //点抄指令下发 logger.Info($"采集服务启动成功,监听端口:{serverPort}"); } catch(Exception ex) { logger.Error($"采集服务启动异常:{ex}"); throw new Exception(ex.Message); } } /// /// 缓存器 /// /// /// private void bufferMemory(SocketClient client, MyFixedHeaderRequestInfo requestInfo,TcpService tcpService) { try { string header = stringChange.bytesToHexStr(requestInfo.Header, requestInfo.Header.Length); string body = stringChange.bytesToHexStr(requestInfo.Body, requestInfo.BodyLength); byte[] buffer = new byte[requestInfo.Header.Length + requestInfo.Body.Length]; Array.Copy(requestInfo.Header, 0, buffer, 0, requestInfo.Header.Length); Array.Copy(requestInfo.Body, 0, buffer, requestInfo.Header.Length, requestInfo.Body.Length); //var db = conn.GetDatabase(); switch (requestInfo.Header[7]) { case 0x21: //登录指令 =>回复登录指令、下发校时指令 //db.StringSet("LoginMessage:" + clientId, body, TimeSpan.FromMinutes(10)); logger.Info($"{client.ID}登录指令,Header:{header};Body:{body}"); bufferAnalysis.LoginMessageHandling(client, buffer, requestInfo.Header.Length + requestInfo.Body.Length,tcpService); break; case 0X24: //心跳指令 //db.StringSet("HeartMessage:" + clientId, body, TimeSpan.FromMinutes(10)); logger.Info($"{client.ID}心跳指令,Header:{header};Body:{body}"); bufferAnalysis.HeartMessageHandlingAsync(client, buffer, requestInfo.Header.Length + requestInfo.Body.Length); break; case 131: //电表数据 //db.StringSet("DnbMessage:" + clientId, body, TimeSpan.FromMinutes(10)); logger.Info($"{client.ID}电表数据,Header:{header};Body:{body}"); bufferAnalysis.EDataMessageHandlingAsync(client, buffer, requestInfo.Header.Length + requestInfo.Body.Length, 1); break; case 132: //水、蒸汽、压缩空气表数据(流量类型) //db.StringSet("FlowMessage:" + clientId, body, TimeSpan.FromMinutes(10)); logger.Info($"{client.ID}水表数据,Header:{header};Body:{body}"); bufferAnalysis.SDataMessageHandling(client, buffer, requestInfo.Header.Length + requestInfo.Body.Length, 1); break; case 147: //电表点抄 //db.StringSet("DnbMessage:" + clientId, body, TimeSpan.FromMinutes(10)); logger.Info($"{client.ID}电表点抄,Header:{header};Body:{body}"); bufferAnalysis.EDataMessageHandlingAsync(client, buffer, requestInfo.Header.Length + requestInfo.Body.Length, 2); break; case 148: //水表点抄 //db.StringSet("FlowMessage:" + clientId, body, TimeSpan.FromMinutes(10)); logger.Info($"{client.ID}水表点抄,Header:{header};Body:{body}"); bufferAnalysis.SDataMessageHandling(client, buffer, requestInfo.Header.Length + requestInfo.Body.Length, 2); break; default: logger.Info($"{client.ID}指令未匹配到对应类型;"); break; } } catch(Exception ex) { logger.Error("缓存器异常", ex); } } /// /// 点抄指令下发 /// private void ReadMeterTask() { try { var t = Task.Run(async delegate { while (true) { //SysConfig sysConfig = baseService.Queryable().InSingle(14); SysConfig sysConfig = SqlSugarHelper.Db.Queryable().InSingle(14); if (sysConfig != null) { if (!string.IsNullOrEmpty(sysConfig.ConfigValue)) { logger.Warn($"通过参数配置获取到点抄表号:{sysConfig.ConfigValue}"); string[] clientIds = sysConfig.ConfigValue.Split('+'); foreach (string item in clientIds) { string clientId = FormatCollectDeviceId(item.Substring(0, 5)); SocketClient[] socketClients = service.GetClients(); foreach (SocketClient socketClient in socketClients) { logger.Warn($"客户端信息打印:{socketClient.ID};{socketClient.IP}"); byte[] buffer = new byte[14]; byte[] collectBuffer = msgUtil.HexStrTorbytes(clientId.Substring(2, 4)); string monitorId = Convert.ToString(msgUtil.ParseToInt(item.Substring(6, 2)), 16).PadLeft(2, '0'); monitorId += Convert.ToString(msgUtil.ParseToInt(item.Substring(8, 2)), 16).PadLeft(2, '0'); byte[] monitorBuffer = msgUtil.HexToString(monitorId); Array.Copy(new byte[] { 0x68, 0x45 }, 0, buffer, 0, 2); Array.Copy(collectBuffer, 0, buffer, 2, collectBuffer.Length); Array.Copy(new byte[] { 0x00, 0xBF, 0x68, 0x06, 0x00, 0x02 }, 0, buffer, 4, 6); Array.Copy(monitorBuffer, 0, buffer, 10, monitorBuffer.Length); /*buffer[10] = Encoding.UTF8.GetBytes(Convert.ToString(msgUtil.ParseToInt(sysConfig.ConfigValue.Substring(6, 2)), 16))[0]; buffer[11] = 0x00;*/ byte csCheck = msgUtil.Check_CS(buffer); buffer[12] = csCheck; buffer[13] = 0x16; socketClient.Send(buffer); logger.Warn($"向客户端:{socketClient.ID};发送点抄指令:{msgUtil.bytesToHexStr(buffer, (int)buffer.Length)}"); } await Task.Delay(100 * 2); } sysConfig.ConfigValue = string.Empty; int result = SqlSugarHelper.Db.Updateable().SetColumns(it => new SysConfig() { ConfigValue = string.Empty, UpdateTime = DateTime.Now }).Where(it => it.ConfigId == 14).ExecuteCommand(); } } else { logger.Warn("参数配置信息获取为空"); } await Task.Delay(1000 * 2); } }); } catch (Exception ex) { logger.Error($"点抄数据异常:{ex.Message}"); } } /// /// 集中器编号格式化=>ClientID /// /// /// private string FormatCollectDeviceId(string deviceId) { byte sensorid1 = Convert.ToByte(deviceId.Substring(1, 2)); byte sensorid2 = Convert.ToByte(deviceId.Substring(3, 2)); byte[] flag = Encoding.Default.GetBytes(deviceId.Substring(0, 1)); string collectDeviceId = Convert.ToInt32(flag[0].ToString("x")) + deviceId.Substring(1); return collectDeviceId; } } }