using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace 欧姆龙EIP调试.EIP { /// /// CIP通信工具类 /// public class CIPHelper { /// /// IP地址 /// public string IpAddress { get; set; } /// /// 通信端口号 /// public int Port { get; set; } public bool IsConnected { get { if (client == null) return false; return client.Connected; } } private Socket client; public int SessionHandle = 0; /// /// 默认无参构造 /// public CIPHelper() { } /// /// 构造方法,传递通信IP与端口 /// public CIPHelper(string ip, int port) { this.IpAddress = ip; this.Port = port; } /// /// 建立连接 /// public void Connect() { //连接 try { client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.Connect(new IPEndPoint(IPAddress.Parse(IpAddress), Port)); } catch (Exception ex) { } } /// /// 注册会话 /// public bool RegisterSession() { //注册会话 if (client != null && client.Connected) { byte[] registerSessionBytes = { (byte)0x65, (byte)0x00, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }; client.Send(registerSessionBytes); Thread.Sleep(20); byte[] rev = new byte[1024]; try { int length = client.Receive(rev); byte[] data = new byte[length]; Array.Copy(rev, 0, data, 0, length); if (data[0] == 0x65) return GetSessionHandle(data); } catch { return false; } } return false; } /// /// 读取标签值 /// /// /// public object ReadTag(string tag) { if (client == null) return null; if (!client.Connected) return null; if (SessionHandle == 0) return null; byte[] d = GetReadTagBytes(tag); client.Send(d); Thread.Sleep(20); byte[] rev = new byte[1024]; try { int length = client.Receive(rev); byte[] data = new byte[length]; Array.Copy(rev, 0, data, 0, length); if (data[0] == 0x6f) return ReadTagVal(data); return null; } catch { return null; } } public bool WriteTag(string tag, object value) { if (client == null) return false; if (!client.Connected) return false; if (SessionHandle == 0) return false; byte[] d = GetWriteTagBytes(tag, value); client.Send(d); Thread.Sleep(20); byte[] rev = new byte[1024]; try { int length = client.Receive(rev); byte[] data = new byte[length]; Array.Copy(rev, 0, data, 0, length); if (data[0] == 0x6f) return WriteTagVal(data); return false; } catch { return false; } } /// /// 注销会话 /// /// public bool UnRegisterSession() { if (client == null) return false; if (!client.Connected) return false; if (SessionHandle == 0) return false; List UnregisterSession = new List(); UnregisterSession.AddRange(new List { (byte)0x66, (byte)0x00, (byte)0x00, (byte)0x00 }); UnregisterSession.AddRange(BitConverter.GetBytes(SessionHandle)); UnregisterSession.AddRange(new List { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }); try { client.Send(UnregisterSession.ToArray()); return true; } catch { return false; } } /// /// 断开连接 /// public void DisConnect() { if (client == null) return; //断开 try { if (IsConnected) { client.Close(); } client = null; SessionHandle = 0; } catch (Exception ex) { client = null; SessionHandle = 0; } } #region Private /// /// 解析写标签数据 /// /// /// private bool WriteTagVal(byte[] data) { int byte_index = 0; short var1 = BitConverter.ToInt16(data, 0);//命令码 short var2 = BitConverter.ToInt16(data, 2);//去除Hearder后的长度 if ((var2 + 24) != data.Length)//24是Hearder封装头的长度 封装头长度+后面报文长度 应该等于总长度 否则报文错误 { return false; } int sessionHandle = BitConverter.ToInt32(data, 4); if (sessionHandle != this.SessionHandle) { //如果会话句柄不一致 返回 return false; } int state = BitConverter.ToInt32(data, 8); if (state != 0) { //会话状态不正确 return false; } //00 00 00 00 01 00 02 00 00 00 00 00 B2 00 08 00 CC 00 00 00 C1 00 00 00 //发送方描述 byte_index = 12; //8 //选项 4字节 byte_index = 20; //接口句柄 4字节 byte_index = 24; //超时 2字节 byte_index = 28; //项数 2字节 byte_index = 30; //连接的地址项 2字节 byte_index = 32; //连接地址项长度 2字节 byte_index = 34; //未连接数据项 2字节 byte_index = 36; //连接长度 2字节 byte_index = 38; //数据开始 byte_index = 40; for (int i = byte_index; i < data.Length; i++) { if (data[i] != 0xCD) continue; //填充字节 1字节 if (BitConverter.ToInt16(data, i + 2) != 0x00) { return true; } return false; } return false; } /// /// 解析读标签数据 /// /// /// private object ReadTagVal(byte[] data) { int byte_index = 0; short var1 = BitConverter.ToInt16(data, 0);//命令码 short var2 = BitConverter.ToInt16(data, 2);//去除Hearder后的长度 if ((var2 + 24) != data.Length)//24是Hearder封装头的长度 封装头长度+后面报文长度 应该等于总长度 否则报文错误 { return null; } int sessionHandle = BitConverter.ToInt32(data, 4); if (sessionHandle != this.SessionHandle) { //如果会话句柄不一致 返回 return null; } int state = BitConverter.ToInt32(data, 8); if (state != 0) { //会话状态不正确 return null; } //发送方描述 byte_index = 12; //8 //选项 4字节 byte_index = 20; //接口句柄 4字节 byte_index = 24; //超时 2字节 byte_index = 28; //项数 2字节 byte_index = 30; //连接的地址项 2字节 byte_index = 32; //连接地址项长度 2字节 byte_index = 34; //未连接数据项 2字节 byte_index = 36; //连接长度 2字节 byte_index = 38; //数据开始 byte_index = 40; for (int i = byte_index; i < data.Length; i++) { if (data[i] != 0xCC) continue; //服务标识 0xCC //填充字节 1字节 if (BitConverter.ToInt16(data, i + 2) != 0x00) // data[var4] != 0x00 || data[var4 + 1] != 0x00) { return null; } //数据类型 short dataType = BitConverter.ToInt16(data, i + 4); if (dataType == 0x00C1)//BOOL { bool value = Convert.ToBoolean(((short)data[i + 6] & 0x00ff) | ((short)data[i + 7] << 8)); return value; } if (dataType == 0x00D1)//byte { byte value = data[i + 6]; return value; } if (dataType == 0x00C3)//int { short value = BitConverter.ToInt16(data, i + 6);// ((short)data[i+6] & 0x00ff) | ((short)data[i+7] << 8); return value; } if (dataType == 0x00C4)//long型 { int value = BitConverter.ToInt32(data, i + 6); return value; } if (dataType == 0x00CA)//float { float value = BitConverter.ToSingle(data, i + 6); return value; } } return null; } /// /// 写标签报文数据 /// /// /// /// private byte[] GetWriteTagBytes(string tag, object value) { byte[] TagStringToAscii; byte[] Var4 = Encoding.Default.GetBytes(tag); if (Var4.Length % 2 == 0) { TagStringToAscii = new byte[Var4.Length]; for (int i = 0; i < Var4.Length; i++) { TagStringToAscii[i] = Var4[i]; } } else { TagStringToAscii = new byte[Var4.Length + 1]; for (int i = 0; i < Var4.Length; i++) { TagStringToAscii[i] = Var4[i]; } TagStringToAscii[Var4.Length] = 0x00; } //CIP协议数据 ================================================= List Cip_Msg = new List(); Cip_Msg.Add((byte)0x4D);//服务标识 Cip_Msg.Add((byte)((TagStringToAscii.Length + 2) / 2));//CIP长度多少字 从标识开始 大读取标签长度结束 Cip_Msg.Add((byte)0x91);//固定 Cip_Msg.Add((byte)TagStringToAscii.Length);//PLC标签长度 多少个字节 Cip_Msg.AddRange(TagStringToAscii);//添加标签 //根据类型 if (value is bool) { Cip_Msg.AddRange(new byte[] { 0xC1, 0x00 }); if ((bool)value) { Cip_Msg.AddRange(new byte[] { 0x01, 0x00 }); } else { Cip_Msg.AddRange(new byte[] { 0x00, 0x00 }); } } else if (value is byte) { Cip_Msg.AddRange(new byte[] { 0xD1, 0x00 }); Cip_Msg.Add((byte)value); } else if (value is short) { Cip_Msg.AddRange(new byte[] { 0xC3, 0x00 }); Cip_Msg.AddRange(BitConverter.GetBytes((short)value)); } else if (value is int) { Cip_Msg.AddRange(new byte[] { 0xC4, 0x00 }); Cip_Msg.AddRange(BitConverter.GetBytes((int)value)); } else if (value is float) { Cip_Msg.AddRange(new byte[] { 0xCA, 0x00 }); Cip_Msg.AddRange(BitConverter.GetBytes((float)value)); } List Slot = new List { (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00 }; //槽号 List Cip_Msg0 = new List(); Cip_Msg0.Add((byte)0x52);//命令 Cip_Msg0.Add((byte)0X02);//请求路径长度 Cip_Msg0.AddRange(new byte[] { 0x20, 0x06, 0x24, 0x01 });//默认请求路径 Cip_Msg0.AddRange(new byte[] { 0x0A, 0xF0 });//默认超时 Cip_Msg0.AddRange(BitConverter.GetBytes((short)Cip_Msg.Count)); //后面报文长度 不包含PLC槽号 Cip_Msg0.AddRange(Cip_Msg);//添加CIP报文 List C_S_D = new List(); C_S_D.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//接口句柄 CIP C_S_D.AddRange(new byte[] { 0x01, 0x00 });//超时时间 默认 C_S_D.AddRange(new byte[] { 0x02, 0x00 });//项数 默认 C_S_D.AddRange(new byte[] { 0x00, 0x00 });//空地址项 默认 C_S_D.AddRange(new byte[] { 0x00, 0x00 });//空地址长度 默认 C_S_D.AddRange(new byte[] { 0xB2, 0x00 });//未连接项 默认 C_S_D.AddRange(BitConverter.GetBytes((short)(Cip_Msg0.Count + Slot.Count)));//CIP报文包的长度 包括槽号 List Header = new List(); Header.AddRange(new byte[] { 0x6F, 0x00 });//命令码 Header.AddRange(BitConverter.GetBytes((short)(Cip_Msg0.Count + C_S_D.Count + Slot.Count)));//后面报文的长度 特定命令数据 和 CIP报文长度 和PLC槽号 Header.AddRange(BitConverter.GetBytes(SessionHandle));//添加会话句柄 Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//添加状态 Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); //发送方描述 Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//选项默认 List EtherNet_IP_CIP_MSG = new List();//单标签读取完整报文 EtherNet_IP_CIP_MSG.AddRange(Header);//添加Header 封装头 EtherNet_IP_CIP_MSG.AddRange(C_S_D);//添加特定命令数据 EtherNet_IP_CIP_MSG.AddRange(Cip_Msg0);//添加CIP报文 EtherNet_IP_CIP_MSG.AddRange(Slot);//添加槽号 return EtherNet_IP_CIP_MSG.ToArray(); } /// /// 读标签报文数据 /// /// /// private byte[] GetReadTagBytes(string tag) { byte[] TagStringToAscii; byte[] Var4 = Encoding.Default.GetBytes(tag); if (Var4.Length % 2 == 0) { TagStringToAscii = new byte[Var4.Length]; for (int i = 0; i < Var4.Length; i++) { TagStringToAscii[i] = Var4[i]; } } else { TagStringToAscii = new byte[Var4.Length + 1]; for (int i = 0; i < Var4.Length; i++) { TagStringToAscii[i] = Var4[i]; } TagStringToAscii[Var4.Length] = 0x00; } //CIP协议数据 ================================================= List Cip_Msg = new List(); Cip_Msg.Add((byte)0x4C);//服务标识 Cip_Msg.Add((byte)((TagStringToAscii.Length + 2) / 2));//CIP长度多少字 从标识开始 大读取标签长度结束 Cip_Msg.Add((byte)0x91);//固定 Cip_Msg.Add((byte)TagStringToAscii.Length);//PLC标签长度 多少个字节 Cip_Msg.AddRange(TagStringToAscii);//添加标签 Cip_Msg.Add((byte)0x01); Cip_Msg.Add((byte)0x00); // 读取长度 List Slot = new List { (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00 }; //槽号 List Cip_Msg0 = new List(); Cip_Msg0.Add((byte)0x52);//命令 Cip_Msg0.Add((byte)0X02);//请求路径长度 Cip_Msg0.AddRange(new byte[] { 0x20, 0x06, 0x24, 0x01 });//默认请求路径 Cip_Msg0.AddRange(new byte[] { 0x0A, 0xF0 });//默认超时 Cip_Msg0.AddRange(BitConverter.GetBytes((short)Cip_Msg.Count)); //后面报文长度 不包含PLC槽号 Cip_Msg0.AddRange(Cip_Msg);//添加CIP报文 List C_S_D = new List(); C_S_D.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//接口句柄 CIP C_S_D.AddRange(new byte[] { 0x01, 0x00 });//超时时间 默认 C_S_D.AddRange(new byte[] { 0x02, 0x00 });//项数 默认 C_S_D.AddRange(new byte[] { 0x00, 0x00 });//空地址项 默认 C_S_D.AddRange(new byte[] { 0x00, 0x00 });//空地址长度 默认 C_S_D.AddRange(new byte[] { 0xB2, 0x00 });//未连接项 默认 C_S_D.AddRange(BitConverter.GetBytes((short)(Cip_Msg0.Count + Slot.Count)));//CIP报文包的长度 包括槽号 List Header = new List(); Header.Add((byte)0x6F); Header.Add((byte)0x00);//命令码 Header.AddRange(BitConverter.GetBytes((short)(Cip_Msg0.Count + C_S_D.Count + Slot.Count)));//后面报文的长度 特定命令数据 和 CIP报文长度 和PLC槽号 Header.AddRange(BitConverter.GetBytes(SessionHandle));//添加会话句柄 Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//添加状态 Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); //发送方描述 Header.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00 });//选项默认 List EtherNet_IP_CIP_MSG = new List();//单标签读取完整报文 EtherNet_IP_CIP_MSG.AddRange(Header);//添加Header 封装头 EtherNet_IP_CIP_MSG.AddRange(C_S_D);//添加特定命令数据 EtherNet_IP_CIP_MSG.AddRange(Cip_Msg0);//添加CIP报文 EtherNet_IP_CIP_MSG.AddRange(Slot);//添加槽号 return EtherNet_IP_CIP_MSG.ToArray(); } /// /// 注册会话结果解析 /// /// /// private bool GetSessionHandle(byte[] data) { //short sessionLength = BitConverter.ToInt16(data, 2);// (Convert.ToInt16(data[3]) * 256) | Convert.ToInt16(data[2]); //byte[] var1 = new byte[4]; //for (int i = 0; i < 4; i++) //{ // var1[i] = data[sessionLength + 4 + i]; //} int state = BitConverter.ToInt32(data, 8); if (state == 0)//判断报文状态 { SessionHandle = BitConverter.ToInt32(data, 4); //SessionHandle = new byte[sessionLength]; //for (int i = 0; i < sessionLength; i++) //{ // SessionHandle[i] = data[4 + i]; //} return true; } else { return false; } } #endregion } }