3、EtherNet/IP协议深度解析:CIP、TCP/UDP封装、隐式/显式报文
好,咱们今天来啃一块硬骨头——EtherNet/IP协议。说实话,这协议刚接触时挺绕的,尤其是它那套CIP对象模型。但别急,我拆开来讲,你跟着走一遍就通了。
3.1 CIP协议:EtherNet/IP的灵魂
EtherNet/IP的核心,其实是CIP——通用工业协议。你想想看,它为什么叫“通用”?因为CIP不光跑在以太网上,还能跑在DeviceNet、ControlNet上。说白了,CIP就是一套统一的“语言”,EtherNet/IP只是它的一个“方言”版本。
我在现场调试时遇到过这么个事:甲方要求用EtherNet/IP连AB的PLC,但传感器是DeviceNet接口。怎么办?其实底层都是CIP,加个网关就能通。这就是CIP的价值——它定义了对象、服务和通信规则,上层网络只管封装就行。
CIP的核心概念:
- 对象(Object):每个设备都是一个对象集合。比如一个变频器,它有“参数对象”、“诊断对象”、“控制对象”。
- 类(Class):对象的模板。比如“变频器类”定义了所有变频器共有的属性和服务。
- 实例(Instance):具体的对象。比如“1号变频器”就是“变频器类”的一个实例。
- 属性(Attribute):对象的数据。比如“当前转速”、“故障代码”。
- 服务(Service):对对象执行的操作。比如“启动”、“停止”、“读取参数”。
嗯,这里要注意:CIP的对象模型是分层的。每个设备必须实现一个“标识对象”(Identity Object),用来告诉网络“我是谁”。我调试时经常先读这个对象,确认设备型号和版本,避免固件不匹配的坑。
3.2 TCP/UDP封装:报文怎么打包的?
EtherNet/IP的报文封装,说白了就是给CIP数据包套上TCP或UDP的“外衣”。但具体怎么套,有讲究。
我个人习惯把封装分成两层:
- 底层封装:标准的以太网帧(MAC地址、IP头、TCP/UDP头)。
- 上层封装:EtherNet/IP特有的封装头(Encapsulation Header)。
这个封装头长什么样?我直接给你看结构:
字节偏移 字段 说明
0-1 命令字 如 0x0065(注册会话)
2-3 长度 数据部分长度
4-7 会话句柄 唯一标识一个会话
8-11 状态码 0x0000表示成功
12-15 发送者上下文 用于匹配请求和响应
16-19 选项 通常为0
20+ 数据 CIP报文或配置数据
为什么要有会话句柄?我在项目中遇到过:一个PLC同时连接十几个设备,每个设备都要建立独立的会话。会话句柄就是用来区分这些连接的。如果句柄冲突,通信就会乱套——嗯,我踩过这个坑。
TCP和UDP的选择,其实很简单:
- TCP(端口 44818):用于显式报文,需要可靠传输。比如参数读写、配置下载。
- UDP(端口 2222):用于隐式报文,追求实时性。比如I/O数据周期性交换。
你想想看,如果I/O数据也用TCP,万一丢包重传,那实时性就完蛋了。所以实时数据走UDP,控制指令走TCP——这是工业以太网的通用套路。
3.3 隐式报文 vs 显式报文
这两个概念,是EtherNet/IP最核心的区分。我刚开始学的时候也迷糊,后来用一句话就记住了:
显式报文 = “你问它答”(请求-响应模式)
隐式报文 = “它主动推”(生产者-消费者模式)
3.3.1 显式报文
显式报文,说白了就是传统的客户端-服务器模式。PLC发一个请求:“把参数100的值读给我”,设备回复:“参数100的值是50”。
它的特点:
- 使用TCP连接,保证可靠
- 报文包含完整的CIP服务路径(如“读属性”)
- 适合配置、诊断、非实时数据交换
- 通信开销大,因为每个报文都要解析
我调试时常用Wireshark抓显式报文。有一次发现设备老是超时,一看报文,原来是PLC发了“读全部参数”的请求,设备要处理几百个参数,响应自然慢。后来改成只读关键参数,问题解决。
3.3.2 隐式报文
隐式报文,是EtherNet/IP的杀手锏。它基于生产者-消费者模型,数据是“推”出来的,不需要每次请求。
举个例子:一个编码器每10ms发一次位置数据,PLC只管收。编码器是生产者,PLC是消费者。如果还有第二个PLC也要这个数据,它也能同时收——这就是多播的好处。
隐式报文的特点:
- 使用UDP,低延迟
- 数据格式预先定义好(通过配置连接)
- 报文头很小,只有连接ID和序列号
- 适合周期性I/O数据、实时控制
我的经验:配置隐式报文时,一定要算好“请求包大小”和“响应包大小”。我曾经遇到一个项目,甲方要求每5ms交换一次数据,但报文太大,UDP包被分片了,导致丢包率飙升。后来把数据拆成两个连接,一个传模拟量,一个传开关量,才稳定下来。
3.4 连接管理:建立通信的握手
无论是隐式还是显式,通信前都要建立“连接”。EtherNet/IP的连接管理分三步:
- TCP连接建立:三次握手,建立底层通道。
- 会话注册:发送“注册会话”命令,获取会话句柄。
- 连接建立:发送“前向打开”请求,指定通信参数(如触发周期、数据大小)。
我见过不少新手,直接跳过会话注册就发数据,结果设备根本不响应。记住:会话句柄就像门禁卡,没有它,设备不认你。
连接建立后,设备会分配一个连接ID。后续的隐式报文就靠这个ID来标识,不需要再带完整的CIP路径。这就是为什么隐式报文效率高——数据头只有几个字节。
3.5 实战:抓包分析一个隐式报文
光说不练假把式。我拿一个实际抓包的数据给你看:
Ethernet II, Src: AB:CD:EF:01:02:03, Dst: 01:00:5E:01:01:01
IP, Src: 192.168.1.10, Dst: 239.192.1.1
UDP, Src Port: 2222, Dst Port: 2222
EtherNet/IP:
.000 0000 0000 0001 = Connection ID: 1
Sequence Number: 4521
Data (8 bytes):
0x41 0x42 0x43 0x44 0x00 0x00 0x00 0x64
你看,这个报文只有连接ID、序列号和8字节数据。没有CIP路径,没有服务码。设备收到后,根据连接ID就知道这8字节对应哪个输入数据块。这就是隐式报文的精髓——轻量、快速。
注意:序列号是用来检测丢包的。如果PLC发现序列号跳变,说明有UDP包丢了。我建议在PLC程序中加一个丢包计数器,一旦超过阈值就报警。我曾经因为没加这个,设备运行了三天才被发现数据有缺失,排查起来非常痛苦。
3.6 总结一下
EtherNet/IP的深度解析,其实就三件事:
- CIP:定义了“说什么”——对象、属性、服务。
- 封装:定义了“怎么说”——TCP/UDP头、封装头。
- 报文类型:定义了“什么时候说”——显式(问-答)和隐式(推-收)。
我个人觉得,理解隐式报文是掌握EtherNet/IP的关键。很多工程师把EtherNet/IP当成普通的TCP/IP来用,结果实时性上不去。记住:实时数据走UDP多播,配置数据走TCP单播——这是铁律。
下一章,我会带你实战配置一个EtherNet/IP从站设备,手把手教你建立连接、交换数据。到时候你会更深刻地理解今天讲的内容。