工业通讯协议(五)- EtherNet/IP
EtherNet/IP是由罗克韦尔自动化公司在1990年代后期开发的工业以太网通讯协议,现由ODVA(开放设备网供应商协会)管理
。其名称中的“IP”并非指互联网协议(Internet Protocol),而是“工业协议”(Industrial Protocol)的缩写。
作为一种应用层协议,EtherNet/IP建立在标准以太网技术之上,采用通用的TCP/IP协议栈,并通过CIP(通用工业协议) 实现设备间的无缝通信。这意味着它既能享受标准以太网的成本优势和技术演进红利,又能满足工业环境对实时性和可靠性的苛刻要求。
EtherNet/IP 技术架构
协议栈分层设计
EtherNet/IP采用了基于OSI参考模型的分层架构,巧妙地将工业通信需求融入标准以太网框架
| OSI层次 | 协议/技术 | 功能说明 |
|---|---|---|
| 物理层 | IEEE 802.3 | 定义电气信号、线缆、接口(如100BASE-TX) |
| 数据链路层 | IEEE 802.3 MAC + VLAN | MAC地址寻址,支持VLAN隔离和QoS |
| 网络层 | IPv4/IPv6 | IP地址分配(静态/DHCP),支持子网划分 |
| 传输层 | TCP(端口44818) + UDP(端口2222) | 显性消息用TCP,隐性消息用UDP |
| 应用层 | CIP(通用工业协议) | 定义设备对象模型、服务接口 |
核心通信机制
关于EtherNet/IP协议中客户端/服务器的区分以及通信机制,其设计相当独特,它并不完全遵循传统IT网络中的客户端/服务器定义,并且同时采用了类似长连接的机制和广播/多播机制,以满足工业控制对实时性和效率的要求。
下面的表格总结了EtherNet/IP协议在不同通信模式下的核心机制:
| 通信模式 | 角色关系 | 连接机制 | 使用的传输层协议 | 主要用途 |
|---|---|---|---|---|
| 显式报文 | 典型的客户端/服务器模型 | 基于TCP的面向连接通信 | TCP | 非实时数据(如配置、参数设置、程序上传下载) |
| 隐式报文 | 生产者/消费者模型 | 基于UDP的广播或多播通信 | UDP | 实时性要求高的I/O数据 |
-
显式报文与客户端/服务器模型
显式报文通信用于传输非实时、需要可靠交付的数据,例如设备配置、参数设定或故障诊断信息。这种通信方式完全符合传统的客户端/服务器模型。在这个模型中:- 客户端是连接的发起者,主动向服务器请求服务或数据。
- 服务器(在工业现场通常是PLC、驱动器等设备)在指定的端口上监听连接请求,并对客户端的请求作出响应。
这种通信基于TCP协议,确保了数据传输的可靠性、顺序性和完整性,其机制类似于我们常说的长连接。
-
隐式报文与生产者/消费者模型
隐式报文用于传输对实时性要求极高的I/O数据(如传感器读数、控制命令)。它采用了一种更高效的生产者/消费者模型。在这个模型中:- 生产者是数据的产生源(例如,一个传感器)。
- 消费者是数据的使用者(例如,多个需要读取该传感器数据的控制器)。
这种通信基于UDP协议。生产者将数据一次性发布到网络上,多个消费者可以同时“订阅”并接收这些数据,而无需生产者为每个消费者单独发送。这种机制通常利用广播或多播方式实现,极大地提高了通信效率,减少了网络延迟。由于UDP是无连接的,它本身不是严格意义上的“长连接”,但其周期性的数据发布模式在效果上实现了一种持续的数据流。
-
EtherNet/IP的显式报文通常使用TCP端口44818,而隐式报文(I/O消息)使用UDP端口2222
报文示例
🔍 TCP 显式报文详解
显式报文用于非实时、需要可靠传输的数据交换,例如设备配置、参数设置和程序上下载。它基于 TCP 协议,确保数据准确无误地送达。
以下是一个用于读取设备身份信息的典型请求报文各层结构详解:
| 协议层 | 字段名 | 示例值 (十六进制) | 含义与用途说明 |
|---|---|---|---|
| 以太网帧头 | 目标MAC地址 | 00 1A 4B C8 D2 4F | 数据帧要发送到的设备的物理地址。 |
| 源MAC地址 | 00 0B 57 75 32 1C | 发送数据帧的设备的物理地址。 | |
| 以太网类型 | 08 00 | 标识载荷(Payload)是 IPv4 数据包。 | |
| IP 报文头 | 版本/首部长度 | 45 | IPv4,首部长度为20字节。 |
| 总长度 | 00 3C | 整个IP数据包的总长度为60字节。 | |
| 协议 | 06 | 表示上层协议是 TCP。 | |
| 源IP地址 | C0 A8 01 64 | 发送方的IP地址(192.168.1.100)。 | |
| 目标IP地址 | C0 A8 01 65 | 接收方的IP地址(192.168.1.101)。 | |
| TCP 段头 | 源端口 | C0 28 (49192) | 发起连接的应用程序端口。 |
| 目标端口 | 13 8B (5003) | EtherNet/IP 显式报文标准端口 (通常为44818,也见5003)。 | |
| 序列号与确认号 | ... | 用于TCP可靠传输的序列和确认机制。 | |
| EtherNet/IP 封装头 | 命令 (Command) | 6F 00 (0x006F) | 封装命令,此处为 SendRRData,表示发送未连接的显式报文。 |
| 长度 (Length) | 04 00 | 后面所跟数据(CIP指令)的长度。 | |
| 会话句柄 (Session Handle) | B2 4C 04 01 | 由目标设备在会话注册时生成的唯一标识,用于维持通信会话。 | |
| CIP 数据部分 | 服务代码 (Service) | 0E | CIP服务代码,0x0E 代表 Get_Attribute_Single(读取单个属性)。 |
| 路径 (Path) | 20 06 24 01 | 指定要访问的CIP对象(此处是Class ID为0x01的身份对象)和实例。 |
应用场合举例:
这种报文典型用于工程师在电脑上使用配置软件(如Rockwell的Studio 5000)连接至一台PLC。当工程师希望查看该PLC的设备信息(如制造商、型号、序列号)时,软件就会构造并发送这样一条读取身份对象的请求报文。PLC收到后,会返回一个包含所请求信息的响应报文。整个过程基于可靠的TCP连接,确保指令和数据的准确交互。
⚡ UDP 隐式报文详解
隐式报文(又称I/O报文)用于传输对实时性要求极高的周期性I/O数据,如传感器读数和控制命令。它基于UDP协议,牺牲部分可靠性以换取速度和效率。
以下是一个用于传输模拟量输入数据的典型报文各层结构详解:
| 协议层 | 字段名 | 示例值 (十六进制) | 含义与用途说明 |
|---|---|---|---|
| 以太网帧头 | 目标MAC地址 | 01 00 5E xx xx xx | 一个多播MAC地址,意味着数据可被多个订阅该地址的设备同时接收。 |
| 源MAC地址 | 00 1D 9C xx xx xx | 数据发送设备(如I/O模块)的物理地址。 | |
| 以太网类型 | 08 00 | 标识载荷是 IPv4 数据包。 | |
| IP 报文头 | 协议 | 11 | 表示上层协议是 UDP。 |
| 源IP地址 | C0 A8 01 0A | 发送方IP地址(192.168.1.10)。 | |
| 目标IP地址 | EF xx xx xx | 一个多播IP地址,用于高效的一对多数据传输。 | |
| UDP 数据报头 | 源端口 | 08 AE (2222) | EtherNet/IP 隐式报文常用源端口。 |
| 目标端口 | 08 AE (2222) | EtherNet/IP 隐式报文标准目标端口。 | |
| 长度 | 00 20 | UDP数据报的总长度。 | |
| EtherNet/IP I/O 数据 | 连接标识符 (Connection ID) | ... | 唯一标识一个已建立的I/O连接,由扫描器(主站)在连接建立时分配。 |
| 序列号 (Sequence Number) | ... | 用于检测数据包是否丢失。 | |
| I/O 数据载荷 | 43 21 00 00 | 核心的实时数据。例如,这4个字节可能表示一个浮点数 165.0(假设是温度传感器读数)。 |
应用场合举例:
在一个汽车装配线的机器人控制单元中,机器人控制器(扫描器)需要实时获取安装在夹具上的多个传感器的数据。这些传感器数据通过UDP隐式报文以多播形式发送。控制器和机器人可以同时“消费”这些数据,从而做出同步的运动控制决策。这种机制延迟极低,确保了生产节拍的高效和精准。
代码实践
由于EtherNet/IP基于以太网,我们无须另外的硬件平台,用PC就可以模拟主站和从站进行通讯,下面给出一个简单的基于EtherNet/IP设备发现示例
从站(服务器)
EtherNet/IP从站相对主站来说较难实现,一般用于真实的设备端(如PLC, IO, 传感器),其实现一般基于C语言的底层实现。
PC上可以用OpENer实现,是一个跨平台的开源EtherNet/IP协议栈。
地址:https://github.com/EIPStackGroup/OpENer
在Windows平台上的编译方法:
从git主页可以了解到,OpENer支持Visual Studio和MingW,本文以MingW为例,直接按照git上介绍的方法操作:

操作完,可以看到\bin\mingw\src\ports\MINGW下有个OpENer.exe生成,亲测,后面的参数用IP无效,用网络适配器的名称可以,如:

.\OpENer.exe "WLAN 2"
如此,就在WLAN 2的网络下启动了一个EtherNet/IP从站节点
主站(客户端)
EtherNet/IP主站实现途径比较多,RA官方也提供了不少相应工具,下面给出Python实现的示例:
用Python基于pycomm3库实现一个简单的EtherNet/IP的扫描程序
from pycomm3 import CIPDriver
def scan_ethernet_ip_nodes():
"""
扫描网络中的EtherNet/IP节点并打印其信息。
"""
try:
# 使用discover方法扫描网络
discovered_devices = CIPDriver.discover()
if discovered_devices:
print(f"发现了 {len(discovered_devices)} 个EtherNet/IP节点:")
print("-" * 60)
for device in discovered_devices:
print(f"IP地址: {device['ip_address']}")
print(f"供应商: {device['vendor']}")
print(f"产品名称: {device['product_name']}")
print(f"产品类型: {device['product_type']}")
print("-" * 60)
else:
print("未发现任何EtherNet/IP节点。")
except Exception as e:
print(f"扫描过程中发生错误: {e}")
if __name__ == "__main__":
scan_ethernet_ip_nodes()
可以发现上述从站设备
抓包
成功建立通讯,就可以用WireShark抓包,可以抓到一个EtherNet/IP包,并可以看到包里的CIP报文内容,可以看出是一条显示报文。


浙公网安备 33010602011771号