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

551 lines
18 KiB

using EC.Util.Common;
using System.Collections.Concurrent;
using System.Net;
using System.Timers;
using Timer = System.Timers.Timer;
namespace JiLinApp.Docking.VibrateAlarm;
public class TcpManager
{
#region Fields
private AsyncTcpServer Server { get; set; }
private TcpManagerConfig Config { get; set; }
private ConcurrentDictionary<string, ClientMessage> DeviceDict { get; } = new();
private Timer HeartTimer { get; } = new();
#region Event
public delegate void VibrateTcpDeviceStateEvent(ClientMessage device);
public delegate void VibrateTcpSensorStateEvent(SensorState sensor);
public delegate void VibrateTcpAlarmEvent(TcpAlarmHostMessage msg);
public event VibrateTcpDeviceStateEvent? OnVibrateTcpDeviceState;
public event VibrateTcpSensorStateEvent? OnVibrateTcpSensorState;
public event VibrateTcpAlarmEvent? OnVibrateTcpAlarm;
#endregion Event
#endregion Fields
public TcpManager()
{
}
#region Server
public void Start(TcpManagerConfig config)
{
if (IsRunning()) return;
Server = new(IPAddress.Any, config.ServerPort);
Server.ClientConnected += Server_ClientConnected;
Server.ClientDisconnected += Server_ClientDisconnected;
Server.DatagramReceived += Server_DatagramReceived;
Server.Start();
HeartTimer.Close();
HeartTimer.Interval = 1000 * config.DeviceHeartKeep;
HeartTimer.Elapsed += HeartTimer_Elapsed;
HeartTimer.Start();
Config = config;
}
public void Stop()
{
if (!IsRunning()) return;
try
{
Server.Stop();
}
finally
{
Server.ClientConnected -= Server_ClientConnected;
Server.ClientDisconnected -= Server_ClientDisconnected;
Server.DatagramReceived -= Server_DatagramReceived;
Server = null;
DeviceDict.Clear();
HeartTimer.Stop();
HeartTimer.Elapsed -= HeartTimer_Elapsed;
}
}
public bool IsRunning()
{
return Server != null && Server.IsRunning();
}
#endregion Server
#region Events
private void HeartTimer_Elapsed(object? sender, ElapsedEventArgs e)
{
foreach (var clientMsg in DeviceDict.Values)
{
if (!clientMsg.IsOnline) continue;
SendHostHeart_01(clientMsg);
}
}
private void Server_ClientConnected(object? sender, TcpClientConnectedEventArgs e)
{
string clientKey = e.TcpClient.Client.RemoteEndPoint?.ToString() ?? "";
if (clientKey == "") return;
string clientIp = clientKey.Split(':')[0];
string clientPort = clientKey.Split(':')[1];
Console.WriteLine("上线:{0}", clientIp);
if (!TryGetDevice(clientIp, out ClientMessage clientMsg))
{
clientMsg = new()
{
Client = e.TcpClient,
Host = new() { Id = -1, Ip = clientIp, Port = clientPort }
};
AddDeivce(clientIp, clientMsg);
}
else
{
ProcessDeviceStateEvent(ref clientMsg, 1);
}
}
private void Server_ClientDisconnected(object? sender, TcpClientDisconnectedEventArgs e)
{
string clientKey = e.TcpClient.Client.RemoteEndPoint?.ToString() ?? "";
if (clientKey == "") return;
string clientIp = clientKey.Split(':')[0];
string clientPort = clientKey.Split(':')[1];
Console.WriteLine("下线:{0}", clientIp);
if (TryGetDevice(clientIp, out ClientMessage clientMsg))
{
ProcessDeviceStateEvent(ref clientMsg, 0);
}
}
private void Server_DatagramReceived(object? sender, TcpDatagramReceivedEventArgs<byte[]> e)
{
string clientKey = e.TcpClient.TcpClient.Client.RemoteEndPoint?.ToString() ?? "";
if (clientKey == "") return;
string clientIp = clientKey.Split(':')[0];
if (TryGetDevice(clientIp, out ClientMessage clientMsg))
{
clientMsg.AddData(e.Datagram);
AnalysisClientMessage(ref clientMsg);
}
}
#endregion Events
#region Analysis
private void AnalysisClientMessage(ref ClientMessage clientMsg)
{
List<byte[]> msglist = clientMsg.GetMessageList();
if (msglist == null || msglist.Count == 0) return;
for (int i = 0; i < msglist.Count; i++)
{
byte[] msg = msglist[i];
bool vaild = msg.Length >= 19 && msg[0] == 0xAA && msg[1] == 0xAA;
Console.WriteLine("Receive from {0}:{1} => {2}, {3}", clientMsg.Ip, clientMsg.Port, DataMessage.ToHexString(msg), vaild);
if (!vaild) continue;
DataMessage mm = new();
mm.Decode(msglist[i]);
switch (mm.FunctionNum)
{
case 0x00:
Console.WriteLine("主机登录:{0}", clientMsg.Ip);
if (clientMsg.Host == null || clientMsg.Host.Id != mm.DeviceId)
{
clientMsg.Host = new() { Id = mm.DeviceId, Ip = mm.SendIp, Port = mm.SendPort.ToString() };
UpdateDevice(clientMsg.Ip, clientMsg.Host);
}
ProcessDeviceStateEvent(ref clientMsg, 1);
ResponseHostLogin_10(clientMsg, mm);
ClientMessage taskClientMsg = clientMsg;
if (taskClientMsg.SensorsEmpty && taskClientMsg.SensorsLock.TryEnterWriteLock(1000))
{
Task.Run(() =>
{
while (taskClientMsg.SensorsEmpty)
{
RequestSensorList_07(taskClientMsg);
Thread.Sleep(1000);
}
taskClientMsg.SensorsLock.ExitWriteLock();
});
}
break;
case 0x01:
Console.WriteLine("心跳:{0}", clientMsg.Ip);
if (clientMsg.Host == null || clientMsg.Host.Id != mm.DeviceId)
{
clientMsg.Host = new() { Id = mm.DeviceId, Ip = mm.SendIp, Port = mm.SendPort.ToString() };
UpdateDevice(clientMsg.Ip, clientMsg.Host);
}
ProcessDeviceStateEvent(ref clientMsg, 1);
break;
case 0x12:
Console.WriteLine("传感器地址设置响应:{0}", clientMsg.Ip);
SetDataRequest(mm, 0x02);
break;
case 0x13:
Console.WriteLine("传感器模式设置响应:{0}", clientMsg.Ip);
SetDataRequest(mm, 0x03);
break;
case 0x14:
Console.WriteLine("传感器轮询状态响应:{0}", clientMsg.Ip);
int sensorAddr = mm.Data[0] + mm.Data[1] * 256;
int state = mm.Data[2] + mm.Data[3] * 256;
int online = state % 2;
int alarm = state / 2 % 2;
ProcessSensorStateEvent(ref clientMsg, mm, sensorAddr, online, alarm);
SetDataRequest(mm, 0x04);
break;
case 0x15:
Console.WriteLine("传感器复位响应:{0}", clientMsg.Ip);
SetDataRequest(mm, 0x05);
break;
case 0x17:
Console.WriteLine("返回传感器列表:{0}", clientMsg.Ip);
if (clientMsg.SensorsEmpty)
{
for (int j = 2; j < mm.Data.Length; j++)
{
sensorAddr = Convert.ToByte((mm.Data[j] + mm.Data[++j] * 256));
SensorState sensor = new(mm.DeviceId, sensorAddr, 0, 0);
clientMsg.SensorDict[sensorAddr] = sensor;
}
RequestSensorsStateActively_08(clientMsg);
}
SetDataRequest(mm, 0x07);
break;
case 0x18:
Console.WriteLine("传感器主动状态响应:{0}", clientMsg.Ip);
SetDataRequest(mm, 0x08);
break;
}
}
}
private void ProcessDeviceStateEvent(ref ClientMessage device, int online)
{
if (device.OnlineState != online)
{
device.OnlineState = online;
ReportDeviceState(device);
}
}
private void ProcessSensorStateEvent(ref ClientMessage client, DataMessage mm, int sensorAddr, int offline, int alarm)
{
if (!client.SensorDict.TryGetValue(sensorAddr, out SensorState? sensor))
{
sensor = new(mm.DeviceId, sensorAddr, offline, alarm);
client.SensorDict[sensorAddr] = sensor;
ReportSensorState(sensor);
}
else if (sensor.OfflineState != offline || sensor.AlarmState != alarm)
{
sensor.OfflineState = offline;
sensor.AlarmState = alarm;
ReportSensorState(sensor);
}
if (alarm == 1)
{
ReportAlarm(sensor.DeviceId, sensorAddr);
//RequestSensorReset_05(clientMsg, sensorAddr);
}
}
private void ReportDeviceState(ClientMessage device)
{
OnVibrateTcpDeviceState?.Invoke(device);
}
private void ReportSensorState(SensorState sensor)
{
OnVibrateTcpSensorState?.Invoke(sensor);
}
private void ReportAlarm(int deviceId, int sensorAddr)
{
TcpAlarmHostMessage alarmMsg = new()
{
AlarmTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
CID = "1151",
DeviceID = deviceId,
SensorAddr = sensorAddr.ToString()
};
OnVibrateTcpAlarm?.Invoke(alarmMsg);
}
#endregion Analysis
#region Send
public bool SendMessage(string ip, byte[] bytes)
{
if (Server == null || !Server.IsRunning()) return false;
if (!TryGetDevice(ip, out ClientMessage clientMsg)) return false;
string cmd = DataMessage.ToHexString(bytes);
DataMessage mm = new();
mm.Decode(bytes);
Console.WriteLine("Send to {0}:{1} => {2}, {3}", ip, clientMsg.Port, cmd, JsonUtil.ToJson(mm));
Server.SendAsync(clientMsg.Client, bytes);
return true;
}
public bool SendRequest(ref DataRequest request)
{
if (request.Request == null) return false;
request.Request.FrameNum = FrameNumber;
FrameNumber++;
bool send = SendMessage(request.Request.ReceiveIp, request.Request.Encode());
return send;
}
public bool SendNoRequest(DataMessage msg)
{
msg.FrameNum = FrameNumber;
FrameNumber++;
bool send = SendMessage(msg.ReceiveIp, msg.Encode());
return send;
}
public bool SendResponse(DataMessage msg)
{
bool send = SendMessage(msg.ReceiveIp, msg.Encode());
return send;
}
public bool SendHostHeart_01(ClientMessage client)
{
if (!client.IsOnline) return false;
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x01, 1);
msg.Data = new byte[] { 0xFF };
return SendNoRequest(msg);
}
public bool RequestSensorChange_02(ClientMessage client, int newSensorAddr)
{
if (!client.IsOnline) return false;
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x02, 4);
msg.Data = new byte[] { (byte)(newSensorAddr % 256), (byte)(newSensorAddr / 256), (100 % 256), (100 / 256) };
DataRequest request = new()
{
Request = msg
};
return SendRequest(ref request);
}
public bool RequestSensorState_04(ClientMessage client, int sensorAddr)
{
if (!client.IsOnline) return false;
if (!client.SensorDict.TryGetValue(sensorAddr, out _)) return false;
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x04, 2);
msg.Data = new byte[] { (byte)(sensorAddr % 256), (byte)(sensorAddr / 256) };
DataRequest request = new()
{
Request = msg
};
return SendRequest(ref request);
}
public bool RequestSensorsState_04(ClientMessage client)
{
if (!client.IsOnline) return false;
if (client.SensorsEmpty) return false;
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x04, 2);
foreach (var item in client.SensorDict.Values)
{
int sensorAddr = item.Addr;
msg.Data = new byte[] { (byte)(sensorAddr % 256), (byte)(sensorAddr / 256) };
DataRequest request = new()
{
Request = msg
};
SendRequest(ref request);
}
return true;
}
public bool RequestSensorReset_05(ClientMessage client, int sensorAddr)
{
if (!client.IsOnline) return false;
if (!client.SensorDict.TryGetValue(sensorAddr, out _)) return false;
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x05, 2);
msg.Data = new byte[] { (byte)(sensorAddr % 256), (byte)(sensorAddr / 256) };
DataRequest request = new()
{
Request = msg
};
return SendRequest(ref request);
}
public bool RequestSensorList_07(ClientMessage client)
{
if (!client.IsOnline) return false;
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x07, 0);
DataRequest request = new()
{
Request = msg
};
return SendRequest(ref request);
}
public bool RequestSensorStateActively_08(ClientMessage client, int sensorAddr)
{
if (!client.IsOnline) return false;
if (!client.SensorDict.TryGetValue(sensorAddr, out _)) return false;
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x08, 2);
msg.Data = new byte[] { (byte)(sensorAddr % 256), (byte)(sensorAddr / 256) };
DataRequest request = new()
{
Request = msg
};
return SendRequest(ref request);
}
public bool RequestSensorsStateActively_08(ClientMessage client)
{
if (!client.IsOnline) return false;
if (client.SensorsEmpty) return false;
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x08, 2);
foreach (var item in client.SensorDict.Values)
{
int sensorAddr = item.Addr;
msg.Data = new byte[] { (byte)(sensorAddr % 256), (byte)(sensorAddr / 256) };
DataRequest request = new()
{
Request = msg
};
SendRequest(ref request);
}
return true;
}
public bool ResponseHostLogin_10(ClientMessage client, DataMessage mm)
{
if (!client.IsOnline) return false;
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x10, 0);
msg.FrameNum = mm.FrameNum;
return SendResponse(msg);
}
#endregion Send
#region ClientMessage
public bool ContainsDevice(string clientIp)
{
return DeviceDict.ContainsKey(clientIp);
}
public ClientMessage GetDevice(string clientIp)
{
return DeviceDict[clientIp];
}
public bool TryGetDevice(string clientIp, out ClientMessage clientMsg)
{
return DeviceDict.TryGetValue(clientIp, out clientMsg);
}
public bool TryGetDevice(int deviceId, out ClientMessage clientMsg)
{
foreach (var item in DeviceDict.Values)
{
if (item.Host.Id == deviceId)
{
clientMsg = item;
return true;
}
}
clientMsg = null;
return false;
}
private bool AddDeivce(string clientIp, ClientMessage clientMsg)
{
if (ContainsDevice(clientIp)) return false;
DeviceDict[clientIp] = clientMsg;
return true;
}
private void SetDevice(string clientIp, ClientMessage clientMsg)
{
DeviceDict[clientIp] = clientMsg;
}
private bool RemoveDevice(string clientIp)
{
return DeviceDict.Remove(clientIp, out _);
}
private bool UpdateDevice(string clientIp, TcpAlarmHost host)
{
if (!DeviceDict.ContainsKey(clientIp)) return false;
DeviceDict[clientIp].Host = host;
return true;
}
public List<ClientMessage> GetDeviceList()
{
return DeviceDict.Values.ToList();
}
#endregion ClientMessage
#region Set
private byte FrameNumber { get; set; } = 0;
private DataMessage GetSendMessageHead(int deviceId, ClientMessage client, byte fun_num, byte datalen)
{
DataMessage msg = new()
{
DeviceId = deviceId,
SendIp = client.Host.Ip,
//SendIp = client.Client.Client.LocalEndPoint.ToString().Split(':')[0],
SendPort = Server.Port,
ReceiveIp = client.Ip,
ReceivePort = int.Parse(client.Port),
FunctionNum = fun_num,
DataLen = datalen
};
return msg;
}
public void SetDataRequest(DataMessage msg, byte functionNum)
{
lock (this)
{
//for (int i = 0; i < Reqlist.Count; i++)
//{
// if (Reqlist[i].Request.FunctionNum == functionNum && Reqlist[i].Request.FrameNum == msg.FrameNum)
// {
// Reqlist[i].Responce = msg;
// }
//}
}
}
#endregion Set
}