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 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 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 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 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 sensorList) { if (!ClientMessageDict.ContainsKey(clientIp)) return false; ClientMessageDict[clientIp].SensorList = sensorList; return true; } #endregion ClientMessage #region Set private List 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 }