using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using ToolKitlib; using CRClib; using System.Threading; using System.ComponentModel.Design; using System.Net.Sockets; using System.Net; using System.Collections; namespace NengLiang { internal class NengLiang { static log4net.ILog log; public static Socket serverSocket; /// /// 在线用户列表 /// public static List idOnLine = new List(); /// /// 存储IP及Socket--便于服务器与指定客户端通信 /// public static Dictionary OnLineDic = new Dictionary(); public static Encoding encoding = Encoding.Default; /// /// 地址码,[变量名,数据类型,可修改可读否(改-读)] ,变量个数 /// public static Dictionary RegisterType;//地址码00对应40001,其他地址以此类推[4区保持寄存器40001~49999](绝对地址) /// /// 循环获取数据时间 /// public static int loopTime = 10; //public static float TRAS = 1000 / 2400 * 12.5f;//3.5字符周期周期时间(单位ms) public static float TRAS = 3.5f * 9 / 2.4f;//3.5字符周期周期时间(单位ms)单条发送周期时间 //public static float TRAS = -1;//3.5字符周期周期时间(单位ms)单条发送周期时间 /// /// 添加数据寄存器信息 /// public static void AddDictionary() { if (RegisterType == null) { RegisterType = new Dictionary(); RegisterType.Add(0, new string[] { "瞬时流量", "ulong", "ny", "2" }); RegisterType.Add(2, new string[] { "供水温度", "uint", "ny", "1" }); RegisterType.Add(3, new string[] { "回水温度", "uint", "ny", "1" }); RegisterType.Add(4, new string[] { "采样值", "uint", "ny", "1" }); RegisterType.Add(5, new string[] { "累计流量整数", "ulong", "ny", "2" }); RegisterType.Add(7, new string[] { "累计流量小数", "uint", "ny", "1" }); RegisterType.Add(8, new string[] { "正累计流量整数", "ulong", "yy", "2" }); RegisterType.Add(10, new string[] { "正累计流量小数", "uint", "ny", "1" }); RegisterType.Add(11, new string[] { "负累计流量整数", "ulong", "yy", "2" }); RegisterType.Add(13, new string[] { "负累计流量小数", "uint", "ny", "1" }); RegisterType.Add(14, new string[] { "瞬时热量", "ulong", "ny", "2" }); RegisterType.Add(16, new string[] { "修改版本号", "uint", "yy", "1" }); RegisterType.Add(17, new string[] { "语言", "uint", "yy", "1" }); RegisterType.Add(18, new string[] { "表地址", "uint", "yy", "1" }); RegisterType.Add(19, new string[] { "仪表通讯速度", "uint", "yy", "1" }); RegisterType.Add(20, new string[] { "修改口径", "uint", "yy", "1" }); RegisterType.Add(21, new string[] { "流量单位", "uint", "yy", "1" }); RegisterType.Add(22, new string[] { "流量积算单位", "uint", "yy", "1" }); RegisterType.Add(23, new string[] { "零点采样值", "uint", "yy", "1" }); RegisterType.Add(24, new string[] { "仪表系数", "uint", "yy", "1" }); RegisterType.Add(25, new string[] { "热量系数", "uint", "yy", "1" }); RegisterType.Add(26, new string[] { "供水温度系数", "uint", "yy", "1" }); RegisterType.Add(27, new string[] { "回水温度系数", "uint", "yy", "1" }); RegisterType.Add(28, new string[] { "小信号切除点", "uint", "yy", "1" }); RegisterType.Add(29, new string[] { "修改脉冲单位", "uint", "yy", "1" }); RegisterType.Add(30, new string[] { "允许切除显示", "uint", "yy", "1" }); RegisterType.Add(31, new string[] { "反向输出允许", "uint", "yy", "1" }); RegisterType.Add(32, new string[] { "电流输出类型", "uint", "yy", "1" }); RegisterType.Add(33, new string[] { "脉冲输出方式", "uint", "yy", "1" }); RegisterType.Add(34, new string[] { "频率输出范围", "uint", "yy", "1" }); RegisterType.Add(35, new string[] { "空管报警允许", "uint", "yy", "1" }); RegisterType.Add(36, new string[] { "空管报警阈值", "uint", "yy", "1" }); RegisterType.Add(37, new string[] { "上限报警允许", "uint", "yy", "1" }); RegisterType.Add(38, new string[] { "上限报警数值", "uint", "yy", "1" }); RegisterType.Add(39, new string[] { "下限报警允许", "uint", "yy", "1" }); RegisterType.Add(40, new string[] { "下限报警数值", "uint", "yy", "1" }); RegisterType.Add(41, new string[] { "励磁报警允许", "uint", "yy", "1" }); RegisterType.Add(42, new string[] { "传感器系数", "uint", "yy", "1" }); RegisterType.Add(43, new string[] { "预留", "uint", "yy", "1" }); RegisterType.Add(44, new string[] { "空管采样值", "uint", "ny", "1" }); RegisterType.Add(45, new string[] { "报警信息", "uint", "ny", "1" }); RegisterType.Add(46, new string[] { "电流零点修正", "uint", "yy", "1" }); RegisterType.Add(47, new string[] { "电流满度修正", "uint", "yy", "1" }); RegisterType.Add(48, new string[] { "仪表量程设置", "uint", "yy", "1" }); RegisterType.Add(49, new string[] { "测量阻尼时间", "uint", "yy", "1" }); RegisterType.Add(50, new string[] { "流量方向选择项", "uint", "yy", "1" }); RegisterType.Add(51, new string[] { "累计热量整数", "ulong", "yy", "2" }); RegisterType.Add(53, new string[] { "累计热量小数", "uint", "yy", "1" }); RegisterType.Add(54, new string[] { "累计冷量整数", "ulong", "yy", "2" }); RegisterType.Add(56, new string[] { "累计冷量小数", "uint", "yy", "1" }); } } static void Main(string[] args) { //初始化日志 log4net.Config.XmlConfigurator.Configure(); log = log4net.LogManager.GetLogger("loginfo"); AddDictionary(); init(); //var a = 0x36213; //ushort b = (ushort)Convert.ToInt16(a, 16); //byte g = (byte)(b / 256);//0x33 //byte d = (byte)(b % 256);//0x2A //Console.ReadKey(); while (true) { if (OnLineDic.Count == 0) continue; Thread.Sleep(1000 * loopTime); var T = (int)Math.Ceiling(TRAS); Console.WriteLine("发送报文间隔:" + T + " 毫秒"); byte devAdd = 0x01; byte code = 0x03; byte[] bytes;// 发送字节 foreach (var v in OnLineDic.Values) { foreach (var item in RegisterType.Keys) { if (TRAS != -1) { Thread.Sleep(T); } else continue; ushort start = (ushort)item; ushort length = ushort.Parse(RegisterType[item][3].ToString()); bytes = ReadKsepRsgistecs(devAdd, code, start, length); log.Info("发送至" + v.RemoteEndPoint + ": " + ToolKit.byteArrayToHexString(bytes)); //Console.WriteLine(ToolKit.byteArrayToHexString(bytes)); v.Send(bytes); } } } } /// /// 初始化服务器 /// public static void init() { //TCP try { //var ip = "172.17.0.9"; //var port = 12303; var ip = "127.0.0.1"; var port = 12303; //调用socket(函数创建一个用于通信的套接字。 serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //给已经创建的套接宁绑定一个端口号 IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(ip), port); serverSocket.Bind(endPoint); //调用listen(函数使套接宁成为—个监听 serverSocket.Listen(1000);//最大连接数 //开启监听任务 Task.Run(new Action(() => { ListenConnection(); })); //开启输入任务 Task.Run(new Action(() => { BaudRate(); })); } catch (Exception e) { Console.WriteLine("服务器初始化异常:" + e.Message); } } /// /// 设置波特率 /// private static void BaudRate() { while (true) { try { TRAS = float.Parse(Console.ReadLine().ToString()); } catch (Exception e) { Console.WriteLine("输入波特率错误:" + e.Message); } } } /// /// 监听任务 /// private static void ListenConnection() { while (true) { //调用accept() 函数来接受客户端的连接 Socket clientSocket = serverSocket.Accept();//新用户连接后触发返回新的socket string ipPort = clientSocket.RemoteEndPoint.ToString();//连接用户的IP及端口 addOnLine(ipPort, clientSocket, true); Console.WriteLine(clientSocket.RemoteEndPoint.ToString() + "上线了"); Task.Run(() => ReceiveMsg(clientSocket));//针对单个客户端开启线程(接收) } } /// /// 接收消息--接收到进入触发 /// /// private static void ReceiveMsg(Socket clientSocket) { StringBuilder builder_shuju = new StringBuilder("");//需校验字节 StringBuilder builder_crc = new StringBuilder("");//收到检验位 while (true) { byte[] bytes = new byte[1024]; int length = -1; try { length = clientSocket.Receive(bytes);//返回字节数 } catch (Exception) { //用户下线--更新在线列表 addOnLine(clientSocket.RemoteEndPoint.ToString(), clientSocket, false); Console.WriteLine(clientSocket.RemoteEndPoint.ToString() + "下线了"); break;//结束线程 } if (length == 0) { //用户下线--更新在线列表 addOnLine(clientSocket.RemoteEndPoint.ToString(), clientSocket, false); Console.WriteLine(clientSocket.RemoteEndPoint.ToString() + "下线了"); break;//结束线程 } if (length > 0) { //string message = Encoding.Default.GetString(bytes, 0, length); string _message = ToolKit.byteArrayToHexString(bytes, length);//带空格报文 string message = _message.Replace(" ", "");//不带空格报文 //CRC校验--失败返回不解析 builder_shuju.Clear(); builder_crc.Clear(); for (int i = 0; i < message.Length - 4; i++) { builder_shuju.Append(message[i]); } for (int i = message.Length - 4; i < message.Length; i++) { builder_crc.Append(message[i]); } if (CRC.CRCForModbus(builder_shuju.ToString().ToUpper()) != builder_crc.ToString().ToUpper()) { log.Info("接收" + clientSocket.RemoteEndPoint + "数据校验失败" + ": " + _message); Console.WriteLine("接收" + clientSocket.RemoteEndPoint + "数据校验失败" + ": " + _message); } else { //执行解析 log.Info("接收到" + clientSocket.RemoteEndPoint + ": " + _message); JudgmentFunction(message); } } } } /// /// 更新在线用户列表 /// /// 用户IP端口号套接 /// Socket /// 用是否增加 private static void addOnLine(string clientIp, Socket clientSocket, bool isAdd) { try { if (isAdd) { idOnLine.Add(clientIp); OnLineDic.Add(clientIp, clientSocket); } else { idOnLine.Remove(clientIp); OnLineDic.Remove(clientIp); } } catch (Exception e) { Console.WriteLine("更新在线用户异常:" + e.Message); } //Invoke(new Action(() => //{ // if (isAdd) { idOnLine.Add(clientIp); } // else { idOnLine.Remove(clientIp); } //})); } /// /// 判断功能类型 /// /// public static void JudgmentFunction(string message) { try { string order = message[2].ToString() + message[3].ToString();//命令 StringBuilder Register = new StringBuilder("");//类型 for (int i = 4; i < 8; i++) { Register.Append(message[i]); } var key = int.Parse(ToolKit.hexStr2Str(Register.ToString().Trim())); if (order == "03")//读取命令 { if (!RegisterType.ContainsKey(key) || RegisterType[key][2][1] == 'n') return; readData(message, key); } else if (order == "10") //修改命令 { if (!RegisterType.ContainsKey(key) || RegisterType[key][2][0] == 'n') return; } } catch (Exception e) { Console.WriteLine("判断功能类型异常:" + e.Message); } } /// /// 读取保存寄存器指令 /// /// 地址 /// 功能码 /// 起始地址 /// 变量个数 /// public static byte[] ReadKsepRsgistecs(byte devAdd, byte code, ushort start, ushort length) { //拼接报文 List sendCommand = new List();//地址 + 功能码 + 起始地址 + 变量个数 + 校验码 sendCommand.Add(devAdd);//地址 sendCommand.Add(code);//功能码 sendCommand.Add((byte)(start / 256));//起始地址--高位 sendCommand.Add((byte)(start % 256));//起始地址--地位 sendCommand.Add((byte)(length / 256));//变量个数--高位 sendCommand.Add((byte)(length % 256));//变量个数--地位 byte[] astr = ToolKit.listToBytes(sendCommand); string a = CRC.CRCForModbus(ToolKit.byteArrayToHexString(astr)); sendCommand.Add(ToolKit.stringToByteArray(a)[0]); //校验码-- 高位 sendCommand.Add(ToolKit.stringToByteArray(a)[1]); //校验码-- 地位 //发送报文 //sendCommand.ToArray(); //Thread.Sleep(40); byte[] bytes = ToolKit.listToBytes(sendCommand); //接收报文 //校验报文--验证长度--验证站--验证功能码 //解析报文 return bytes; } /// /// 读取命令 /// /// /// 地址码 public static void readData(string message, int key) { try { string _readSum = message[4].ToString() + message[5].ToString(); int readSum = int.Parse(ToolKit.hexStr2Str(_readSum));//变量总字节数 StringBuilder builder = new StringBuilder(""); for (int i = 6; i < 6 + readSum * 2; i++) { builder.Append(message[i]); } var num = Convert.ToInt64(builder.ToString().Trim(), 16);//获取值 var aa = RegisterType[key][1].ToLower(); if (aa == "ulong") { var number = (ulong)num; analysisUnit(RegisterType[key][0], number); } else { var number = (uint)num; analysisUnit(RegisterType[key][0], number); } } catch (Exception e) { Console.WriteLine("读取命令异常:" + e.Message); } } /// /// unit值类型解析 /// /// 变量名 /// public static void analysisUnit(string name, uint number) { if (name == "供水温度") { Console.WriteLine(name + ":" + number + "℃"); } else if (name == "回水温度") { Console.WriteLine(name + ":" + number + "℃"); } else if (name == "采样值") { Console.WriteLine(name + ":" + number); } else if (name == "累计流量小数") { Console.WriteLine(name + ":0." + number); } else if (name == "正累计流量小数") { Console.WriteLine(name + ":0." + number); } else if (name == "负累计流量小数") { Console.WriteLine(name + ":0." + number); } else if (name == "修改版本号") { Console.WriteLine(name + ":" + number); } else if (name == "语言") { if (number == 0) Console.WriteLine(name + ":中文"); else if (number == 1) Console.WriteLine(name + ":英文"); } else if (name == "表地址") { Console.WriteLine(name + ":" + number); } else if (name == "仪表通讯速度") { //float TRAS;//3.5字符周期周期时间(单位ms) if (number == 0) { Console.WriteLine(name + ":300"); /*TRAS = 1000 / 300 * 12.5f;*/ TRAS = 3.5f * 9 / 0.3f; } else if (number == 1) { Console.WriteLine(name + ":2400"); /*TRAS = 1000 / 2400 * 12.5f;*/ TRAS = 3.5f * 9 / 2.4f; } else if (number == 2) { Console.WriteLine(name + ":14400"); /*TRAS = 1000 / 14400 * 12.5f; */TRAS = 3.5f * 9 / 14.4f; } else if (number == 3) { Console.WriteLine(name + ":600"); /*TRAS = 1000 / 600 * 12.5f; */TRAS = 3.5f * 9 / 0.6f; } else if (number == 4) { Console.WriteLine(name + ":4800");/* TRAS = 1000 / 4800 * 12.5f;*/ TRAS = 3.5f * 9 / 4.8f; } else if (number == 5) { Console.WriteLine(name + ":19200"); /*TRAS = 1000 / 19200 * 12.5f;*/ TRAS = 3.5f * 9 / 19.2f; } else if (number == 6) { Console.WriteLine(name + ":1200"); /*TRAS = 1000 / 1200 * 12.5f; */TRAS = 3.5f * 9 / 1.2f; } else if (number == 7) { Console.WriteLine(name + ":9600"); /*TRAS = 1000 / 9600 * 12.5f;*/ TRAS = 3.5f * 9 / 9.6f; } else if (number == 8) { Console.WriteLine(name + ":38400"); /*TRAS = 1000 / 38400 * 12.5f;*/ TRAS = 3.5f * 9 / 38.4f; } } else if (name == "修改口径") { Console.WriteLine(name + ":" + number); } else if (name == "流量单位") { if (number == 0) Console.WriteLine(name + ":L/H"); else if (number == 1) Console.WriteLine(name + ":L/M"); else if (number == 2) Console.WriteLine(name + ":L/S"); else if (number == 3) Console.WriteLine(name + ":M³/H"); else if (number == 4) Console.WriteLine(name + ":M³/M"); else if (number == 5) Console.WriteLine(name + ":M³/S"); } else if (name == "流量积算单位") { if (number == 0) Console.WriteLine(name + ":0.001L"); else if (number == 1) Console.WriteLine(name + ":0.001M³"); else if (number == 2) Console.WriteLine(name + ":0.01L"); else if (number == 3) Console.WriteLine(name + ":0.1L"); else if (number == 4) Console.WriteLine(name + ":1L"); else if (number == 5) Console.WriteLine(name + ":0.01M³"); else if (number == 6) Console.WriteLine(name + ":0.1M³"); else if (number == 7) Console.WriteLine(name + ":1M³"); } else if (name == "零点采样值") { Console.WriteLine(name + ":" + number); } else if (name == "仪表系数") { Console.WriteLine(name + ":" + number); } else if (name == "热量系数") { Console.WriteLine(name + ":" + number); } else if (name == "供水温度系数") { Console.WriteLine(name + ":" + number); } else if (name == "回水温度系数") { Console.WriteLine(name + ":" + number); } else if (name == "小信号切除点") { Console.WriteLine(name + ":" + number); } else if (name == "修改脉冲单位") { Console.WriteLine(name + ":" + number); } else if (name == "允许切除显示") { if (number == 0) Console.WriteLine(name + ":允许"); else if (number == 1) Console.WriteLine(name + ":禁止"); } else if (name == "反向输出允许") { if (number == 0) Console.WriteLine(name + ":允许"); else if (number == 1) Console.WriteLine(name + ":禁止"); } else if (name == "电流输出类型") { if (number == 0) Console.WriteLine(name + ":0~10mA"); else if (number == 1) Console.WriteLine(name + ":4~20mA"); } else if (name == "脉冲输出方式") { if (number == 0) Console.WriteLine(name + ":频率"); else if (number == 1) Console.WriteLine(name + ":脉冲"); } else if (name == "频率输出范围") { Console.WriteLine(name + ":" + number); } else if (name == "空管报警允许") { if (number == 0) Console.WriteLine(name + ":允许"); else if (number == 1) Console.WriteLine(name + ":禁止"); } else if (name == "空管报警阈值") { Console.WriteLine(name + ":" + number); } else if (name == "上限报警允许") { if (number == 0) Console.WriteLine(name + ":允许"); else if (number == 1) Console.WriteLine(name + ":禁止"); } else if (name == "上限报警数值") { Console.WriteLine(name + ":" + number); } else if (name == "下限报警允许") { if (number == 0) Console.WriteLine(name + ":允许"); else if (number == 1) Console.WriteLine(name + ":禁止"); } else if (name == "下限报警数值") { Console.WriteLine(name + ":" + number); } else if (name == "励磁报警允许") { if (number == 0) Console.WriteLine(name + ":允许"); else if (number == 1) Console.WriteLine(name + ":禁止"); } else if (name == "传感器系数") { Console.WriteLine(name + ":" + number); } else if (name == "预留") { Console.WriteLine(name + ":" + number); } else if (name == "空管采样值") { Console.WriteLine(name + ":" + number); } else if (name == "报警信息") { if (number == 1) Console.WriteLine(name + ":瞬时流量单位选择错误"); else if (number == 2) Console.WriteLine(name + ":空管"); else if (number == 4) Console.WriteLine(name + ":下限报警"); else if (number == 8) Console.WriteLine(name + ":上限报警"); } else if (name == "电流零点修正") { Console.WriteLine(name + ":" + number); } else if (name == "电流满度修正") { Console.WriteLine(name + ":" + number); } else if (name == "仪表量程设置") { Console.WriteLine(name + ":" + number); } else if (name == "测量阻尼时间") { Console.WriteLine(name + ":" + number); } else if (name == "流量方向选择项") { Console.WriteLine(name + ":" + number); } else if (name == "累计热量小数") { Console.WriteLine(name + ":0." + number); } else if (name == "累计冷量小数") { Console.WriteLine(name + ":0." + number); } } /// /// ulong值类型解析 /// /// 变量名 /// public static void analysisUnit(string name, ulong number) { if (name == "瞬时流量") { number /= 1000;//此值单位为升 / 小时,需要除以 1000 得到立方米 / 小时 Console.WriteLine(name + ":" + number + "m³/h"); } else if (name == "累计流量整数") { Console.WriteLine(name + ":" + number); } else if (name == "正累计流量整数") { Console.WriteLine(name + ":" + number); } else if (name == "负累计流量整数") { Console.WriteLine(name + ":" + number); } else if (name == "瞬时热量")//单位为 KJ/h(千焦每小时),若想得到 MJ/h 则需要除以 1000;换算成 KWh/h 需要除以 3600, { Console.WriteLine(name + ":" + number + "KJ/h"); } else if (name == "累计热量整数") { Console.WriteLine(name + ":" + number); } else if (name == "累计冷量整数") { Console.WriteLine(name + ":" + number); } } /// /// 寄存器类型 /// public enum qRegisterType { //不可修改可读 瞬时流量, 供水温度 = 2, 回水温度, 采样值, 累计流量整数, 累计流量小数 = 7, //可修改可读 正累计流量整数, //不可修改可读 正累计流量小数 = 10, //可修改可读 负累计流量整数, //不可修改可读 负累计流量小数 = 13, 瞬时热量, //可修改可读 修改版本号 = 16, 语言, 表地址, 仪表通讯速度, 修改口径, 流量单位, 流量积算单位, 零点采样值, 仪表系数, 热量系数, 供水温度系数, 回水温度系数, 小信号切除点, 修改脉冲单位, 允许切除显示, 反向输出允许, 电流输出类型, 脉冲输出方式, 频率输出范围, 空管报警允许, 空管报警阈值, 上限报警允许, 上限报警数值, 下限报警允许, 下限报警数值, 励磁报警允许, 传感器系数, 预留, //不可修改可读 空管采样值, 报警信息, //可修改可读 电流零点修正, 电流满度修正, 仪表量程设置, 测量阻尼时间, 流量方向选择项, 累计热量整数, 累计热量小数 = 53, 累计冷量整数, 累计冷量小数 = 56, } } }