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#

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);
}
};
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,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);
}
}
/// <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;
}
}
}