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.
541 lines
18 KiB
541 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> ClientMessageDict { get; } = new();
|
|
|
|
private Timer HeartTimer { get; } = new();
|
|
|
|
private Timer StateSpanTimer { get; } = new();
|
|
|
|
#region Event
|
|
|
|
public delegate void TcpDeviceMessageEvent(TcpAlarmHost host, string msg);
|
|
|
|
public delegate void TcpSensorMessageEvent(TcpAlarmHost host, TcpSensorTable section, string msg);
|
|
|
|
public delegate void TcpSensorStateChangeEvent(SensorState state);
|
|
|
|
public delegate void TcpSensorAlarmEvent(TcpAlarmHostMessage msg);
|
|
|
|
public event TcpDeviceMessageEvent? OnTcpDeviceMessage;
|
|
|
|
public event TcpSensorMessageEvent? OnTcpSensorMessage;
|
|
|
|
public event TcpSensorStateChangeEvent? OnTcpSensorStateChange;
|
|
|
|
public event TcpSensorAlarmEvent? OnTcpSensorAlarm;
|
|
|
|
#endregion Event
|
|
|
|
#endregion Fields
|
|
|
|
public TcpManager()
|
|
{
|
|
}
|
|
|
|
#region Server
|
|
|
|
public void Start(TcpManagerConfig config)
|
|
{
|
|
if (IsRunning()) return;
|
|
try
|
|
{
|
|
Server = new(IPAddress.Any, config.ServerPort);
|
|
Server.ClientConnected += Server_ClientConnected;
|
|
Server.ClientDisconnected += Server_ClientDisconnected;
|
|
Server.DatagramReceived += Server_DatagramReceived;
|
|
Server.Start();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return;
|
|
}
|
|
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;
|
|
ClientMessageDict.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 ClientMessageDict.Values)
|
|
{
|
|
SendHostHeart_01(clientMsg);
|
|
}
|
|
}
|
|
|
|
private void StateSpanTimer_Elapsed(object? sender, ElapsedEventArgs e)
|
|
{
|
|
foreach (var clientMsg in ClientMessageDict.Values)
|
|
{
|
|
RequestSensorState_04(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 (!TryGetClientMessage(clientIp, out ClientMessage clientMsg))
|
|
{
|
|
clientMsg = new()
|
|
{
|
|
Client = e.TcpClient,
|
|
Host = new() { Id = -1, Ip = clientIp, Port = clientPort, Name = "未知设备" }
|
|
};
|
|
AddClientMessage(clientIp, clientMsg);
|
|
}
|
|
if (OnTcpDeviceMessage != null)
|
|
{
|
|
TcpAlarmHost host = clientMsg.Host ?? new() { Id = -1, Ip = clientIp, Port = clientPort, Name = "未知设备" };
|
|
OnTcpDeviceMessage(host, "报警主机上线");
|
|
}
|
|
}
|
|
|
|
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 (TryGetClientMessage(clientIp, out ClientMessage clientMsg))
|
|
{
|
|
RemoveClientMessage(clientIp);
|
|
if (OnTcpDeviceMessage != null)
|
|
{
|
|
TcpAlarmHost host = clientMsg.Host ?? new() { Id = -1, Ip = clientIp, Port = clientPort, Name = "未知设备" };
|
|
OnTcpDeviceMessage(host, "报警主机下线");
|
|
}
|
|
}
|
|
}
|
|
|
|
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 (TryGetClientMessage(clientIp, out ClientMessage clientMsg))
|
|
{
|
|
clientMsg.AddData(e.Datagram);
|
|
AnalysisClientMessage(clientMsg);
|
|
}
|
|
}
|
|
|
|
#endregion Events
|
|
|
|
#region Analysis
|
|
|
|
private void AnalysisClientMessage(ClientMessage clientMsg)
|
|
{
|
|
//AA AA 01 C0 A8 01 64 88 13 C0 A8 01 05 28 23 74 00 01 01 18
|
|
//AA AA 01 C0 A8 01 05 28 23 C0 A8 01 64 88 13 7C 04 02 04 00 2B
|
|
//AA AA 01 C0 A8 01 64 88 13 C0 A8 01 05 28 23 24 14 04 0A 00 02 00 03
|
|
List<byte[]> msglist = clientMsg.GetMessageList();
|
|
if (msglist == null || msglist.Count == 0) return;
|
|
for (int i = 0; i < msglist.Count; i++)
|
|
{
|
|
DataMessage mm = new();
|
|
mm.Decode(msglist[i]);
|
|
Console.WriteLine("Receive from {0}:{1} => {2}, {3}", clientMsg.Ip, clientMsg.Port, DataMessage.ToHexString(msglist[i]), JsonUtil.ToJson(mm));
|
|
TcpAlarmHost host;
|
|
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(), Name = "未知设备" };
|
|
UpdateClientMessage(clientMsg.Ip, clientMsg.Host);
|
|
}
|
|
ResponseHostLogin_10(clientMsg, mm);
|
|
if (clientMsg.SensorListEmpty && clientMsg.SensorListLock.TryEnterWriteLock(1000))
|
|
{
|
|
Task.Run(() =>
|
|
{
|
|
while (clientMsg.SensorListEmpty)
|
|
{
|
|
RequestSensorList_07(clientMsg);
|
|
Thread.Sleep(1000);
|
|
}
|
|
clientMsg.SensorListLock.ExitWriteLock();
|
|
});
|
|
}
|
|
if (OnTcpDeviceMessage != null)
|
|
{
|
|
host = clientMsg.Host ?? new() { Id = mm.DeviceId, Ip = mm.SendIp, Port = mm.SendPort.ToString(), Name = "未知设备" };
|
|
OnTcpDeviceMessage(host, "报警主机登录");
|
|
}
|
|
break;
|
|
|
|
case 0x01:
|
|
Console.WriteLine("心跳:{0}", clientMsg.Ip);
|
|
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;
|
|
if (clientMsg.Host == null || clientMsg.Host.Id != mm.DeviceId)
|
|
{
|
|
clientMsg.Host = new() { Id = mm.DeviceId, Ip = mm.SendIp, Port = mm.SendPort.ToString(), Name = "未知设备" };
|
|
UpdateClientMessage(clientMsg.Ip, clientMsg.Host);
|
|
}
|
|
ProcessOnlineEvent(clientMsg, mm, sensorAddr, online);
|
|
ProcessAlarmEvent(clientMsg, mm, sensorAddr, alarm);
|
|
UpdateOnLineAlarm(clientMsg, sensorAddr, online, alarm);
|
|
SetDataRequest(mm, 0x04);
|
|
if (alarm == 1)
|
|
{
|
|
RequestSensorReset_05(clientMsg);
|
|
}
|
|
break;
|
|
|
|
case 0x15:
|
|
Console.WriteLine("传感器复位响应:{0}", clientMsg.Ip);
|
|
SetDataRequest(mm, 0x05);
|
|
break;
|
|
|
|
case 0x17:
|
|
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(), Name = "设备" };
|
|
UpdateClientMessage(clientMsg.Ip, clientMsg.Host);
|
|
}
|
|
if (clientMsg.SensorListEmpty)
|
|
{
|
|
List<byte> sensorList = new();
|
|
for (int j = 2; j < mm.Data.Length; j++)
|
|
{
|
|
sensorList.Add(Convert.ToByte((mm.Data[j] + mm.Data[++j] * 256)));
|
|
}
|
|
clientMsg.SensorList = sensorList;
|
|
UpdateClientMessage(clientMsg.Ip, sensorList);
|
|
RequestSensorState_04(clientMsg);
|
|
}
|
|
SetDataRequest(mm, 0x07);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ProcessOnlineEvent(ClientMessage client, DataMessage mm, int channel, int online)
|
|
{
|
|
if (client.SectionTable.ContainsKey(channel))
|
|
{
|
|
SensorState oldState = client.SectionTable[channel] as SensorState;
|
|
if (oldState.online == online) return;
|
|
}
|
|
TcpAlarmHost host = client.Host;
|
|
TcpSensorTable section = new() { DeviceId = host.Id, Name = "未知传感器", Channel = channel.ToString() };
|
|
OnTcpSensorMessage?.Invoke(host, section, online == 0 ? "传感器上线" : "传感器离线");
|
|
}
|
|
|
|
private void ProcessAlarmEvent(ClientMessage client, DataMessage mm, int channel, int alarm)
|
|
{
|
|
if (client.SectionTable.ContainsKey(channel))
|
|
{
|
|
SensorState oldState = client.SectionTable[channel] as SensorState;
|
|
if (oldState.alarm == alarm) return;
|
|
}
|
|
TcpAlarmHost host = client.Host;
|
|
if (alarm == 1)
|
|
{
|
|
ProcessAlarm(host.Id, channel);
|
|
}
|
|
}
|
|
|
|
private void UpdateOnLineAlarm(ClientMessage client, int channel, int online, int alarm)
|
|
{
|
|
if (client.SectionTable.ContainsKey(channel))
|
|
{
|
|
SensorState oldState = client.SectionTable[channel] as SensorState;
|
|
oldState.online = online;
|
|
oldState.alarm = alarm;
|
|
OnTcpSensorStateChange?.Invoke(oldState);
|
|
}
|
|
else
|
|
{
|
|
TcpAlarmHost host = client.Host;
|
|
SensorState state = new(host.Id, channel, online, alarm);
|
|
client.SectionTable[channel] = state;
|
|
OnTcpSensorStateChange?.Invoke(state);
|
|
}
|
|
}
|
|
|
|
private void ProcessAlarm(int deviceId, int channel)
|
|
{
|
|
TcpAlarmHostMessage alarmMsg = new()
|
|
{
|
|
AlarmTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
CID = "1151",
|
|
DeviceID = deviceId,
|
|
SensorAddr = channel.ToString()
|
|
};
|
|
OnTcpSensorAlarm?.Invoke(alarmMsg);
|
|
}
|
|
|
|
#endregion Analysis
|
|
|
|
#region Send
|
|
|
|
public bool SendMessage(string ip, byte[] bytes)
|
|
{
|
|
if (Server == null || !Server.IsRunning()) return false;
|
|
if (!TryGetClientMessage(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.Host == null) 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)
|
|
{
|
|
if (client.Host == null || client.Host.Id < 0) return false;
|
|
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x02, 4);
|
|
int channel = 10;
|
|
msg.Data = new byte[] { (byte)(channel % 256), (byte)(channel / 256), (100 % 256), (100 / 256) };
|
|
DataRequest request = new()
|
|
{
|
|
Request = msg
|
|
};
|
|
SendRequest(ref request);
|
|
return true;
|
|
}
|
|
|
|
public bool RequestSensorState_04(ClientMessage client)
|
|
{
|
|
if (client.Host == null || client.Host.Id < 0) return false;
|
|
if (client.SensorListEmpty) return false;
|
|
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x04, 2);
|
|
foreach (var item in client.SensorList)
|
|
{
|
|
int channel = item;
|
|
msg.Data = new byte[] { (byte)(channel % 256), (byte)(channel / 256) };
|
|
DataRequest request = new()
|
|
{
|
|
Request = msg
|
|
};
|
|
SendRequest(ref request);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool RequestSensorReset_05(ClientMessage client)
|
|
{
|
|
if (client.Host == null || client.Host.Id < 0) return false;
|
|
if (client.SensorListEmpty) return false;
|
|
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x05, 2);
|
|
foreach (var item in client.SensorList)
|
|
{
|
|
int channel = item;
|
|
msg.Data = new byte[] { (byte)(channel % 256), (byte)(channel / 256) };
|
|
DataRequest request = new()
|
|
{
|
|
Request = msg
|
|
};
|
|
SendRequest(ref request);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool RequestSensorList_07(ClientMessage client)
|
|
{
|
|
if (client.Host == null || client.Host.Id < 0) return false;
|
|
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x07, 0);
|
|
DataRequest request = new()
|
|
{
|
|
Request = msg
|
|
};
|
|
return SendRequest(ref request);
|
|
}
|
|
|
|
public bool ResponseHostLogin_10(ClientMessage client, DataMessage mm)
|
|
{
|
|
if (client.Host == null) return false;
|
|
DataMessage msg = GetSendMessageHead(client.Host.Id, client, 0x10, 0);
|
|
msg.FrameNum = mm.FrameNum;
|
|
return SendResponse(msg);
|
|
}
|
|
|
|
#endregion Send
|
|
|
|
#region ClientMessage
|
|
|
|
private bool ContainsClientMessage(string clientIp)
|
|
{
|
|
return ClientMessageDict.ContainsKey(clientIp);
|
|
}
|
|
|
|
private ClientMessage GetClientMessage(string clientIp)
|
|
{
|
|
return ClientMessageDict[clientIp];
|
|
}
|
|
|
|
private bool TryGetClientMessage(string clientIp, out ClientMessage clientMsg)
|
|
{
|
|
return ClientMessageDict.TryGetValue(clientIp, out clientMsg);
|
|
}
|
|
|
|
private bool AddClientMessage(string clientIp, ClientMessage clientMsg)
|
|
{
|
|
if (ContainsClientMessage(clientIp)) return false;
|
|
ClientMessageDict[clientIp] = clientMsg;
|
|
return true;
|
|
}
|
|
|
|
private void SetClientMessage(string clientIp, ClientMessage clientMsg)
|
|
{
|
|
ClientMessageDict[clientIp] = clientMsg;
|
|
}
|
|
|
|
private bool RemoveClientMessage(string clientIp)
|
|
{
|
|
return ClientMessageDict.Remove(clientIp, out _);
|
|
}
|
|
|
|
private bool UpdateClientMessage(string clientIp, TcpAlarmHost host)
|
|
{
|
|
if (!ClientMessageDict.ContainsKey(clientIp)) return false;
|
|
ClientMessageDict[clientIp].Host = host;
|
|
return true;
|
|
}
|
|
|
|
private bool UpdateClientMessage(string clientIp, List<byte> sensorList)
|
|
{
|
|
if (!ClientMessageDict.ContainsKey(clientIp)) return false;
|
|
ClientMessageDict[clientIp].SensorList = sensorList;
|
|
return true;
|
|
}
|
|
|
|
#endregion ClientMessage
|
|
|
|
#region Set
|
|
|
|
private List<DataRequest> Reqlist { get; } = new();
|
|
|
|
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.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
|
|
}
|