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的“外衣”。但具体怎么套,有讲究。

我个人习惯把封装分成两层:

  1. 底层封装:标准的以太网帧(MAC地址、IP头、TCP/UDP头)。
  2. 上层封装: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的连接管理分三步:

  1. TCP连接建立:三次握手,建立底层通道。
  2. 会话注册:发送“注册会话”命令,获取会话句柄。
  3. 连接建立:发送“前向打开”请求,指定通信参数(如触发周期、数据大小)。

我见过不少新手,直接跳过会话注册就发数据,结果设备根本不响应。记住:会话句柄就像门禁卡,没有它,设备不认你。

连接建立后,设备会分配一个连接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从站设备,手把手教你建立连接、交换数据。到时候你会更深刻地理解今天讲的内容。