You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
12 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<TcpServer> lazy = new Lazy<TcpServer>(() => 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.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<CheckClearPlugin>().SetDuration(new TimeSpan(0, 0, 0, 5, 0));
}))
.Start();//启动
ReadMeterTask(); //点抄指令下发
logger.Info($"采集服务启动成功,监听端口:{serverPort}");
}
catch(Exception ex)
{
logger.Error($"采集服务启动异常:{ex}");
throw new Exception(ex.Message);
}
}
/// <summary>
/// 缓存器
/// </summary>
/// <param name="clientId"></param>
/// <param name="requestInfo"></param>
private void bufferMemory(SocketClient client, MyFixedHeaderRequestInfo requestInfo)
{
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);
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);
}
}
/// <summary>
/// 点抄指令下发
/// </summary>
private void ReadMeterTask()
{
try
{
var t = Task.Run(async delegate
{
while (true)
{
//SysConfig sysConfig = baseService.Queryable<SysConfig>().InSingle(14);
SysConfig sysConfig = SqlSugarHelper.Db.Queryable<SysConfig>().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<SysConfig>().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}");
}
}
/// <summary>
/// 集中器编号格式化=>ClientID
/// </summary>
/// <param name="monitorId"></param>
/// <returns></returns>
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;
}
}
}