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 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);
byte devAdd = 0x01;
byte code = 0x03;
byte[] bytes;// 发送字节
foreach (var v in OnLineDic.Values)
{
foreach (var item in RegisterType.Keys)
{
Thread.Sleep((int)Math.Ceiling(TRAS));
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 = "172.16.1.49";
//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();
}));
}
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,
}
}
}