using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Sockets; using System.Net; using System.Text; using System.Threading.Tasks; using System.Web.Configuration; namespace Rs.Framework { public class ModbusTcp { Socket m_socket; string m_ip; int m_port; bool isConnected = false; int timeout = 2000; Stopwatch stopWatch = new Stopwatch(); public ModbusTcp(string ip, int port) { m_ip = ip; m_port = port; m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); } public string GetIp() { return m_ip; } public bool Connect() { try { IPEndPoint ipaddr = new IPEndPoint(IPAddress.Parse(m_ip), m_port); m_socket.Connect(ipaddr); isConnected = true; return true; } catch (Exception) { return false; } } /// /// 获取读取报文 /// /// /// /// /// /// public byte[] GetReadCommand(int deviceID, FunCode funCode, int startAddr, int readLen) { List readData = new List(); //添加通信标识 readData.Add(0x00); readData.Add(0x00); //添加协议标识 readData.Add(0x00); readData.Add(0x00); //报文长度(读取报文的长度是固定的6个字节) readData.Add(0x00); readData.Add(0x06); //添加设备编号 readData.Add((byte)deviceID); //添加功能码 readData.Add((byte)funCode); //添加读取地址 readData.Add((byte)(startAddr >> 8)); readData.Add((byte)startAddr); //添加读取长度 readData.Add((byte)(readLen >> 8)); readData.Add((byte)readLen); return readData.ToArray(); } private byte[] GetWriteCommand(int deviceID, FunCode funCode, int startAddr, byte[] writeData, int datalen = 0) { List readData = new List(); //添加通信标识 readData.Add(0x00); readData.Add(0x00); //添加协议标识 readData.Add(0x00); readData.Add(0x00); //计算后面报文的长度 if (funCode == FunCode.WriteSingleCoil || funCode == FunCode.WriteSingleRegister) { readData.Add(0x00); readData.Add(0x06); } else if (funCode == FunCode.WriteMultiCoil || funCode == FunCode.WriteMultiRegister) { int len = 6 + 1 + writeData.Length; readData.Add((byte)(len >> 8)); readData.Add((byte)len); } //添加设备编号 readData.Add((byte)deviceID); //添加功能码 readData.Add((byte)funCode); //添加写入地址 readData.Add((byte)(startAddr >> 8)); readData.Add((byte)startAddr); //添加要写入的线圈的数量 if (funCode == FunCode.WriteMultiCoil || funCode == FunCode.WriteMultiRegister) { readData.Add((byte)(datalen >> 8)); readData.Add((byte)datalen); //添加要写入数据的字节数 readData.Add((byte)writeData.Length); } //添加真实要写入的数据 readData.AddRange(writeData); return readData.ToArray(); } public ModbusErrorCode ReadUshortArr(int deviceID, FunCode funCode, int startAddr, int readLen, out int[] result) { result = new int[readLen]; if (isConnected) { List receiveBuffer = new List(); byte[] readDatas = GetReadCommand(deviceID, funCode, startAddr, readLen); try { int len = m_socket.Send(readDatas); if (len > 0) { //开始接收数据 stopWatch.Restart(); while (true && stopWatch.ElapsedMilliseconds <= timeout) { int receiveDataLen = m_socket.Available; if (receiveDataLen > 0) { byte[] buffer = new byte[receiveDataLen]; len = m_socket.Receive(buffer, receiveDataLen, SocketFlags.None); if (len > 0) { receiveBuffer.AddRange(buffer); //判断数据是否接收完毕, if (receiveBuffer.Count >= 6) { //读取报文长度 int packetLen = receiveBuffer[4] << 8 | receiveBuffer[5]; if (receiveBuffer.Count == packetLen + 6) { int dataLen = receiveBuffer[8]; //代表数据已经接受完毕,开始解析数据 for (int i = 0; i < dataLen / 2; i++) { result[i] = receiveBuffer[(i * 2) + 9] << 8 | receiveBuffer[(i * 2) + 10]; } } } return ModbusErrorCode.OK; } } } if (stopWatch.ElapsedMilliseconds >= timeout) { return ModbusErrorCode.TIMEOUT; } } else { return ModbusErrorCode.SENDFAIL; } } catch (Exception ex) { return ModbusErrorCode.EXCEPTION; } return ModbusErrorCode.OK; } else { //未连接 return ModbusErrorCode.NOCONNECT; } } public ModbusErrorCode WriteSingleCoil(int deviceID, int startAddr, bool flag) { byte[] writeData = new byte[2] { 0x00, 0x00 }; List receiveBuffer = new List(); if (flag) { writeData[0] = 0xFF; writeData[1] = 0x00; } return Write(deviceID, FunCode.WriteSingleCoil, startAddr, writeData); } public ModbusErrorCode WriteCoils(int deviceID, int startAddr, bool[] flags) { byte[] writeData = new byte[((flags.Length - 1) / 8) + 1]; int val = 0; for (int i = 0; i < flags.Length; i++) { if (flags[i]) val = val | 1 << i; else val = val | 0 << i; } for (int i = 0; i < writeData.Length; i++) { writeData[i] = (byte)(val >> (i * 8)); } return Write(deviceID, FunCode.WriteMultiCoil, startAddr, writeData, flags.Length); } public ModbusErrorCode WriteSingleRegister(int deviceID, int startAddr, ushort value) { byte[] writeData = new byte[2] { 0x00, 0x00 }; List receiveBuffer = new List(); writeData[0] = (byte)(value >> 8); writeData[1] = (byte)value; return Write(deviceID, FunCode.WriteSingleRegister, startAddr, writeData); } public ModbusErrorCode WriteMultiHoldRegister(int deviceID, int startAddr, ushort[] values) { byte[] writeData = new byte[values.Length * 2]; for (int i = 0; i < values.Length; i++) { writeData[(i * 2)] = (byte)(values[i] >> 8); writeData[(i * 2) + 1] = (byte)(values[i]); } return Write(deviceID, FunCode.WriteMultiRegister, startAddr, writeData, values.Length); } private ModbusErrorCode Write(int deviceID, FunCode funCode, int startAddr, byte[] writeData, int writeLen = 0) { if (isConnected) { lock (this) { byte[] readDatas = GetWriteCommand(deviceID, funCode, startAddr, writeData, writeLen); try { List receiveBuffer = new List(); int len = m_socket.Send(readDatas); if (len > 0) { //开始接收数据 stopWatch.Restart(); while (true && stopWatch.ElapsedMilliseconds <= timeout) { int receiveDataLen = m_socket.Available; if (receiveDataLen > 0) { byte[] buffer = new byte[receiveDataLen]; len = m_socket.Receive(buffer, receiveDataLen, SocketFlags.None); if (len > 0) { receiveBuffer.AddRange(buffer); if (receiveBuffer.Count >= 6) { ////判断数据是否接收完毕 int framelen = receiveBuffer[4] << 8 | receiveBuffer[5]; if (framelen + 6 == receiveBuffer.Count) { return ModbusErrorCode.OK; } } } } } if (stopWatch.ElapsedMilliseconds >= timeout) { return ModbusErrorCode.TIMEOUT; } } else { return ModbusErrorCode.SENDFAIL; } } catch (Exception ex) { return ModbusErrorCode.EXCEPTION; } return ModbusErrorCode.OK; } } else { //未连接 return ModbusErrorCode.NOCONNECT; } } } public enum FunCode { /// /// 读取 多个线圈(位) /// ReadMultiCoil = 01, /// /// 读取 多个离散量输入量(位) /// ReadMultiInput = 02, /// /// 读取 多个保持寄存器(16进制整型) /// ReadMultiHoldRegister = 03, /// /// 读取 多个输入寄存器(16进制整型) /// ReadMultiInputRegister = 04, /// /// 写入 单个线圈(位) /// WriteSingleCoil = 05, /// /// 写入 单个寄存器(16进制整型) /// WriteSingleRegister = 06, /// /// 写入 多个线圈(位) /// WriteMultiCoil = 15, /// /// 写入 多个寄存器(16进制整型) /// WriteMultiRegister = 16 } public enum ModbusErrorCode { OK, NOCONNECT, SENDFAIL, EXCEPTION, TIMEOUT } }