1 private TcpListener tcpListener;
1 static bool isEnable = false; //是否加载成功 2 static bool isSend = false; //是否发送成功 3 static bool isRead = false; //是否读取成功
启动服务
1 public void StartServer() 2 { 3 if (tcpListener == null) 4 { 5 tcpListener = new TcpListener(IPAddress.Parse("0.0.0.0"), 9003); 6 tcpListener.Start(); 7 Console.WriteLine("启动服务:9003"); 8 while (true) 9 { 10 TcpClient tcpClient = tcpListener.AcceptTcpClient(); 11 System.Threading.Tasks.Task.Factory.StartNew(() => DoListener(tcpClient)); 12 Thread.Sleep(100); 13 } 14 } 15 }
打开监听
1 private void DoListener(TcpClient tcpClient) 2 { 3 tcpClient.SendTimeout = 30000; 4 tcpClient.ReceiveTimeout = 30000; 5 //編輯地址 6 ushort ad = 14288; 7 try 8 { 9 10 while (true) 11 { 12 13 if (!isEnable) 14 { 15 Console.WriteLine("重置状态中..."); 16 InitState(tcpClient.Client, 57357, "00000001"); 17 Thread.Sleep(50); 18 continue; 19 } 20 if (!isSend) 21 { 22 Console.WriteLine("写..."); 23 List<byte> data = new List<byte>(255); 24 data.Add(Convert.ToByte(24)); 25 SendInfo(tcpClient.Client, ad, 85, "00000001", 16, data.ToArray()); 26 Thread.Sleep(50); 27 continue; 28 } 29 if (!isRead) 30 { 31 Console.WriteLine("读..."); 32 ReadInfo(tcpClient.Client, ad, 85, DataType.Ushort); 33 Thread.Sleep(50); 34 continue; 35 } 36 } 37 } 38 catch (Exception ex) 39 { 40 Console.WriteLine(ex.ToString()); 41 } 42 }
停止监听
1 public void DisposeServer() 2 { 3 if (tcpListener != null) 4 { 5 tcpListener.Stop(); 6 tcpListener = null; 7 } 8 }
读取数据
1 public static object[] ReadInfo(Socket socket, ushort add, short len, DataType type) 2 { 3 //构建发送报文 4 byte[] data = BuidReadMessage(add, len); 5 socket.Send(data, data.Length, SocketFlags.None); 6 int size = len * 2 + 7; 7 byte[] rdata = new byte[size]; 8 socket.Receive(rdata, size, SocketFlags.None); 9 Console.WriteLine("从" + add + "获取数据(" + len + "):" + StringUtils.ByteToHex(rdata)); 10 //判断是否成功。 11 if ((rdata[0] == data[0] && rdata[1] == data[1])) 12 { 13 isRead = true; 14 List<object> listData = new List<object>(); 15 for (int i = 3; i < rdata[2] + 3;) 16 { 17 //listData.Add(BitConverter.ToUInt16(rdata, i)); 18 //i += 2; 19 if (type == DataType.Ushort) 20 { 21 listData.Add(BitConverter.ToUInt16(new byte[] { rdata[i + 1], rdata[i] }, 0)); 22 i += 2; 23 } 24 else if (type == DataType.Int) 25 { 26 listData.Add(BitConverter.ToInt32(new byte[] { rdata[i + 1], rdata[i], rdata[i + 3], rdata[i + 2] }, 0)); 27 i += 4; 28 } 29 else if (type == DataType.Binary) 30 { 31 string strBase1 = Convert.ToString(rdata[i], 2).PadLeft(8, '0'); 32 string strBase2 = Convert.ToString(rdata[i + 1], 2).PadLeft(8, '0'); 33 listData.Add(ReverseString(strBase2) + ReverseString(strBase1)); 34 i += 2; 35 } 36 else if (type == DataType.Bit) 37 { 38 string strBase1 = Convert.ToString(rdata[i], 1); 39 listData.Add(rdata[i]); 40 i += 1; 41 } 42 else 43 { 44 listData.Add(System.Text.Encoding.UTF8.GetString(rdata, 3, rdata[2])); 45 i += rdata[2]; 46 } 47 } 48 return listData.ToArray(); 49 } 50 return new object[0]; 51 }
写入
1 public static void SendInfo(Socket socket, ushort add, short len, string type, short fCode, byte[] toValues) 2 { 3 byte[] data= BuildSendMessage(add, toValues, len,type,fCode); 4 socket.Send(data, data.Length, SocketFlags.None); 5 byte[] rdata = new byte[10]; 6 socket.Receive(rdata, 10, SocketFlags.None); 7 //判断是否成功 8 if (data[0] == rdata[0] && data[1] == rdata[1]) 9 isSend = true; 10 }
构建读取报文
1 public static byte[] BuidReadMessage(ushort add,short len) 2 { 3 byte[] addr = StringUtils.DataConvertToBytes(add); 4 byte[] length = StringUtils.DataConvertToBytes(len); 5 List<byte> data = new List<byte>(255); 6 7 data.Add(Convert.ToByte(1)); 8 data.Add(Convert.ToByte(3)); //功能码 9 data.AddRange(addr); 10 data.AddRange(length); 11 byte[] dataBuff = CRC.ToModbusCRC16Byte(data.ToArray(), true); 12 data.AddRange(dataBuff); 13 return data.ToArray(); 14 }
构建发送报文
1 public static byte[] BuildSendMessage(ushort add, byte[] toValues, short len,string type, short fCode) 2 { 3 short id = 1; 4 List<byte> data = new List<byte>(255); 5 data.Add(Convert.ToByte(id)); 6 data.Add(Convert.ToByte(fCode)); 7 data.AddRange(StringUtils.DataConvertToBytes(add)); 8 data.AddRange(StringUtils.DataConvertToBytes(len)); 9 data.Add(Convert.ToByte(Math.Ceiling(Convert.ToDecimal(len) / 8))); 10 byte[] b = new byte[data.Count+ toValues.Length]; 11 Array.Copy(data.ToArray(), 0, b, 0, data.Count); 12 Array.Copy(toValues, 0, b, data.Count, toValues.Length); 13 byte[] dataBuff = new byte[2]; 14 dataBuff = CRC.ToModbusCRC16Byte(b, true); 15 data.AddRange(toValues); 16 data.AddRange(dataBuff); 17 return data.ToArray(); 18 }
读取到的数值转换
1 private static string ReverseString(string value) 2 { 3 char[] ch = value.ToArray();//把文本框你的内容转换为char类型数组 4 Array.Reverse(ch, 0, value.Length);//使用Array类的Reverse方法颠倒数据 5 return new StringBuilder().Append(ch).ToString();//获取指定数组的字符串显示到控件 6 }
重置状态
1 public static void InitState(Socket socket,ushort add,string type) 2 { 3 try 4 { 5 byte[] data = BuildSendMessage1(add, type, 1); 6 socket.Send(data, data.Length, SocketFlags.None); 7 byte[] rdata = new byte[10]; 8 socket.Receive(rdata, rdata.Length, SocketFlags.None); 9 //判断是否成功 10 if (rdata[0] == data[0] && rdata[1] == data[1]) 11 isEnable = true; 12 } 13 catch (Exception ex) 14 { 15 Console.WriteLine(ex.ToString()); 16 } 17 }
ModBus和PLC进行交互流程是:通过socket 发送报文,然后接收到返回的结果。
报文格式:
读 路由 功能码 地址 长度 校验码
写 路由 功能码 地址 长度 字节数量 写入的数据 校验码
是读是写依靠功能码去区别。线圈和寄存器的区别,线圈存储的是 0/1,只能存储一个Bool;寄存器可以存储数据
常用的功能码
1 读取线圈
3 读取寄存器
5 写单个寄存器
15 写线圈
16 写多个寄存器