using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Xml; using System.Xml.Linq; namespace ConsoleApp3 { public class LCDAUE800DService { private static ushort[] crcTable = new ushort[]{ 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 }; private static Dictionary Keys = new Dictionary { { "1","有功电度"}, { "2","有功功率"}, { "3","无功电度"}, { "4","无功功率"}, { "5","A相电压"}, { "6","B相电压"}, { "7","C相电压"}, { "8","A相电流"}, { "9","B相电流"}, { "10","C相电流"}, { "11","功率因数"}, { "12","A相功率"}, { "13","B相功率"}, { "14","C相功率"}, { "15","水燃气当前流量"}, { "16","结算日热量"}, { "17","当前热量"}, { "18","热功率"}, { "19","瞬时流量"}, { "20","当前累计流量"}, { "21","供水温度"}, { "22","回水温度"}, { "23","累计时间"}, { "24","累计时间"}, { "25","自定义2"}, { "26","自定义3"} }; private List _frame = new List(); private int _frameLength = 0; private TcpClient _client; private string _mac; public LCDAUE800DService(TcpClient client) { this._client = client; } public void Run() { var stream = _client.GetStream(); byte[] buffer = new byte[10240]; int bufferLength; while (_client.Connected) { if (stream.DataAvailable) { try { bufferLength = stream.Read(buffer); var rawData = buffer.Take(bufferLength).ToArray(); Console.WriteLine($"from {_client.Client.RemoteEndPoint}:{rawData.Length}"); UnitHandle(stream, rawData); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } } private void UnitHandle(NetworkStream stream, byte[] data) { var start = BitConverter.ToString(data.Take(4).ToArray()).Replace("-", "").ToLower(); var length = data.Length; if (start == "aa55aa55") { var unitLength = 4 + 4 + BitConverter.ToInt32(data.Skip(4).Take(4).ToArray()) + 2 + 4; if (length == unitLength) { Console.WriteLine("单个包"); Handle(stream, data); } else if (length > unitLength) { Console.WriteLine("多个包"); Handle(stream, data.Take(unitLength).ToArray()); UnitHandle(stream, data.Skip(unitLength).ToArray()); } else if (length < unitLength) { Console.WriteLine("长包开头"); _frame.Clear(); _frame.AddRange(data); _frameLength = unitLength; } } else { if (_frame.Count + length == _frameLength) { Console.WriteLine("长包结尾"); _frame.AddRange(data); Handle(stream, _frame.ToArray()); _frame.Clear(); } else if (_frame.Count + length > _frameLength) { Console.WriteLine("长包结尾+后续包"); _frame.AddRange(data.Take(length - _frame.Count)); Handle(stream, _frame.ToArray()); Handle(stream, data.Skip(length - _frame.Count).ToArray()); } else if (_frame.Count + length < _frameLength) { Console.WriteLine("长包中间"); _frame.AddRange(data); } } } private void Handle(NetworkStream stream, byte[] rawData) { var xml = GetXml(rawData); Console.WriteLine("收到客户端的消息:"); Console.WriteLine(FormatXml(xml)); var type = GetTypeFromXml(xml); Console.WriteLine($"type:{type}"); if (type == "request") { HandleRequest(stream, xml); } else if (type == "md5") { HandleMd5(stream, xml); } else if (type == "device") { HandleDevice(stream, xml); } else if (type == "notify") { HandleNotify(stream, xml); } else if (type == "report") { HandleReport(stream, xml); } else if (type == "continuous") { HandleReport(stream, xml); } } private void HandleRequest(NetworkStream stream, string xml) { var command = "sequence"; var operation = "operation"; var doc = new XmlDocument(); doc.PreserveWhitespace = true; doc.LoadXml(xml); doc.SelectSingleNode("/root/common/type").InnerText = command; var idValidate = doc.SelectSingleNode("/root/id_validate"); idValidate.Attributes[operation].Value = command; var sequence = doc.CreateElement(command); sequence.InnerText = "01234567"; idValidate.AppendChild(sequence); Reply(stream, doc.OuterXml); } private void HandleMd5(NetworkStream stream, string xml) { var command = "md5"; var operation = "operation"; var doc = new XmlDocument(); doc.PreserveWhitespace = true; doc.LoadXml(xml); var value1 = doc.SelectSingleNode($"/root/id_validate/{command}").InnerText; using var md5 = MD5.Create(); var value2 = BitConverter.ToString(md5.ComputeHash(Encoding.ASCII.GetBytes("01234567IJKLMNOPQRSTUVWX"))).Replace("-", "").ToLower(); doc.SelectSingleNode("/root/common/type").InnerText = command; var idValidate = doc.SelectSingleNode("/root/id_validate"); idValidate.Attributes[operation].Value = "result"; var result = doc.CreateElement("result"); result.InnerText = value1 == value2 ? "pass" : "fail"; idValidate.ReplaceChild(result, doc.SelectSingleNode($"/root/id_validate/{command}")); Reply(stream, doc.OuterXml); } private void HandleDevice(NetworkStream stream, string xml) { var command = "device_ack"; var operation = "operation"; var doc = new XmlDocument(); doc.PreserveWhitespace = true; doc.LoadXml(xml); //building_id //build_no //var building_id = doc.SelectSingleNode("//building_id").InnerText.Trim(); //var buildArea = GetBuildName(building_id); //var buildType = GetBuildType(building_id); //var buildName = doc.SelectSingleNode("//build_name").InnerText.Trim(); //var period = doc.SelectSingleNode("//period").InnerText.Trim(); var mac = doc.SelectSingleNode("//mac").InnerText.Trim().Replace(":", ""); var period = doc.SelectSingleNode("//period").InnerText.Trim(); var factory = doc.SelectSingleNode("//factory").InnerText.Trim(); var hardware = doc.SelectSingleNode("//hardware").InnerText.Trim(); var software = doc.SelectSingleNode("//software").InnerText.Trim(); Console.WriteLine($"factory:{factory},hardware:{hardware},software:{software},mac:{mac}"); //Console.WriteLine($"楼宇建筑编码:{building_id},行政区域:{buildArea},建筑类型:{buildType},建筑名称:{buildName}"); doc.SelectSingleNode("/root/common/type").InnerText = command; var node = doc.SelectSingleNode("/root/device"); node.RemoveAll(); var deviceOperation = doc.CreateAttribute(operation); deviceOperation.Value = command; node.Attributes.Append(deviceOperation); var deviceAck = doc.CreateElement(command); deviceAck.InnerText = "pass"; node.AppendChild(deviceAck); Reply(stream, doc.OuterXml); } //private static string GetBuildName(string building_id) //{ // try // { // var doc = new XmlDocument(); // var file = Path.Combine(AppContext.BaseDirectory, "SDLC", "ZoneCode.xml"); // doc.LoadXml(File.ReadAllText(file)); // var value = doc.SelectSingleNode($"//ConfigData[Value={building_id.Substring(0, 6)}]/Value[2]").InnerText; // return value; // } // catch (Exception ex) // { // Console.WriteLine(ex.ToString()); // return building_id; // } //} //private static string GetBuildType(string building_id) //{ // try // { // var doc = new XmlDocument(); // var file = Path.Combine(AppContext.BaseDirectory, "SDLC", "BuildingSet.xml"); // doc.LoadXml(File.ReadAllText(file)); // var value = doc.SelectSingleNode($"//ConfigData[Value={building_id.Skip(6).Take(1)}]/Value[1]").InnerText; // return value; // } // catch (Exception ex) // { // Console.WriteLine(ex.ToString()); // return building_id; // } //} private void HandleNotify(NetworkStream stream, string xml) { var command = "time"; var operation = "operation"; var doc = new XmlDocument(); doc.PreserveWhitespace = true; doc.LoadXml(xml); doc.SelectSingleNode("/root/common/type").InnerText = command; var node = doc.SelectSingleNode("/root/heart_beat"); node.RemoveAll(); var deviceOperation = doc.CreateAttribute(operation); deviceOperation.Value = command; node.Attributes.Append(deviceOperation); var deviceAck = doc.CreateElement(command); deviceAck.InnerText = DateTime.Now.ToString("yyyyMMddHHmmss"); node.AppendChild(deviceAck); Reply(stream, doc.OuterXml); //set //var building_id = doc.SelectSingleNode("//building_id").InnerText.Trim(); //doc.SelectSingleNode("//building_id").InnerText = building_id; //var gateway_id = doc.SelectSingleNode("//gateway_id").InnerText.Trim(); //var doc2 = new XmlDocument(); //doc2.PreserveWhitespace = true; //var xml2 = @$"{building_id}{gateway_id}period1"; //doc2.LoadXml(xml2); //Reply(stream, doc2.OuterXml); } //private void HandleContinuous(NetworkStream stream, string xml) //{ // //续传数据处理 // var doc = new XmlDocument(); // doc.PreserveWhitespace = true; // doc.LoadXml(xml); // var building_id = doc.SelectSingleNode("//building_id").InnerText.Trim(); // var gateway_id = doc.SelectSingleNode("//gateway_id").InnerText.Trim(); // //续传数据响应 // var doc2 = new XmlDocument(); // var xml2 = @$"{building_id}{gateway_id}report_ackpass"; // doc2.LoadXml(xml2); // Reply(stream, doc2.OuterXml); //} private void HandleReport(NetworkStream stream, string xml) { //上传数据处理 var doc = new XmlDocument(); doc.PreserveWhitespace = true; doc.LoadXml(xml); var type = doc.SelectSingleNode("//type").InnerText; var building_id = doc.SelectSingleNode("//building_id").InnerText.Trim(); var gateway_id = doc.SelectSingleNode("//gateway_id").InnerText.Trim(); var time = doc.SelectSingleNode("//time").InnerText; var meters = doc.SelectNodes("//meter"); foreach (XmlNode meter in meters) { var deviceNo = meter.SelectSingleNode("//functionex"); var equipidex = deviceNo.Attributes["equipidex"].Value.Trim(); var tpex = deviceNo.Attributes["tpex"].Value.Trim(); var deviceNumber = $"lcdaue800d:{equipidex}"; var functions = meter.SelectNodes("//function"); foreach (XmlNode function in functions) { var key = function.Attributes["id"].Value.Trim(); var value = Keys[key]; Console.WriteLine($"type:{type},time:{time},devicd number:{deviceNumber},item:{value},value:{function.InnerText.Trim()}"); } } //上传数据响应 var doc2 = new XmlDocument(); var xml2 = @$"{building_id}{gateway_id}report_ackpass"; doc2.LoadXml(xml2); Reply(stream, doc2.OuterXml); } private object GetDeviceType(string value) { throw new NotImplementedException(); } private void Reply(NetworkStream stream, string xml) { Console.WriteLine("服务端响应:"); Console.WriteLine(FormatXml(xml)); Console.WriteLine(); using var ms = new MemoryStream(); ms.Write(new byte[] { 0xaa, 0x55, 0xaa, 0x55 });//header var data = new byte[] { 0x00, 0x00, 0x00, 0x00 }.Concat(AesEncrypt(Encoding.UTF8.GetBytes(xml))).ToArray(); ms.Write(BitConverter.GetBytes(data.Length));//length ms.Write(data);//data ms.Write(BitConverter.GetBytes((ushort)XmlGetCrc16(data)));//crc ms.Write(new byte[] { 0x68, 0x68, 0x16, 0x16 }); var response = ms.ToArray(); stream.Write(response); stream.Flush(); } private static string GetTypeFromXml(string xml) { var doc = new XmlDocument(); doc.LoadXml(xml); return doc.SelectSingleNode("/root/common/type").InnerText; } private static string GetXml(byte[] rawData) { var dataLength = BitConverter.ToUInt32(rawData.Skip(4).Take(4).ToArray()); var data = rawData.Skip(8).Take((int)dataLength).ToArray(); var xmlData = data.Skip(4).ToArray(); var crc = BitConverter.ToUInt16(rawData.Skip(8 + (int)dataLength).Take(2).ToArray()); var crc2 = XmlGetCrc16(data); if (crc == crc2) { var result = Encoding.UTF8.GetString(AesDecrypt(xmlData)); result = result.Trim(); if (!result.EndsWith(">")) { Console.WriteLine("xml format error"); result += ">"; } return result; } throw new Exception("crc error"); } private static byte[] HexStringToByteArray(string hex) { return Enumerable.Range(0, hex.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) .ToArray(); } private static uint XmlGetCrc16(byte[] data) { uint crc = 0, by; for (int i = 0; i < data.Length; i++) { by = (crc >> 8) & 0xff; crc = (crc & 0xffff) << 8; crc = (crc ^ crcTable[(data[i] ^ by) & 0xff]) & 0xffff; } return crc; } private static byte[] AesEncrypt(byte[] plainText) { using var aes = CreateAes(); using var encryptor = aes.CreateEncryptor(); return encryptor.TransformFinalBlock(plainText, 0, plainText.Length); } private static byte[] AesDecrypt(byte[] cipherText) { using var aes = CreateAes(); using var decryptor = aes.CreateDecryptor(); return decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length); } private static Aes CreateAes() { var key = HexStringToByteArray("0102030405060708090a0b0c0d0e0f10"); var iv = HexStringToByteArray("0102030405060708090a0b0c0d0e0f10"); var aesAlg = Aes.Create(); aesAlg.Mode = CipherMode.CBC; aesAlg.Padding = PaddingMode.Zeros; aesAlg.BlockSize = 128; aesAlg.Key = key; aesAlg.IV = iv; return aesAlg; } private static string FormatXml(string xml) { try { var doc = new XmlDocument(); doc.LoadXml(xml); var xdoc = XDocument.Parse(doc.OuterXml); return xdoc.ToString(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); return xml; } } } }