
简介这份资源是一套面向工业自动化与上位机开发者的C#以太网通信例程由国外工程师编写用于解决AB PLCAllen Bradley与PC之间实时数据交互的问题适合具备一定C#基础、希望掌握PLC通信编程的开发者参考学习。压缩包共45个文件约308KB以vb源码、resx与resources资源文件、exe可执行程序、manifest清单、xml配置及sln解决方案文件为主另含dll库、pfx证书与settings配置完整保留了Visual Studio工程结构与调试信息。例程围绕建立连接、设备发现、数据映射、读写操作、错误处理、持续监控与关闭连接等关键环节展开代码可直接在VS中打开调试帮助读者理解如何借助RSNetworx for Ethernet/IP等库实现PLC状态读取与输出控制。目前已有261人学习下载可作为工业通信项目开发的实用参考范例。1. 从一份老外写的 AB PLC 以太网通讯 C# 例程说起手上拿到一个压缩包名字叫「AB PLC 与 PC 通过以太网进行通讯 C# 例程 是个老外编写的程序.zip」很多人第一反应是解压、找 sln、点运行。但真到车间里你会发现能不能跑通跟代码写得好不好关系不大卡住你的往往是 RSLinx 的驱动没配对、PLC 的 IP 段跟 PC 不在一个网、或者 ControlLogix 的槽号填错。AB PLCAllen-Bradley罗克韦尔自动化旗下品牌在汽车、冶金、水处理这些行业存量极大上位机用 C# 通过以太网读写它的标签是工控上位机方向最典型的一类需求。这份例程的价值不在代码本身多优雅而在于它把「PC 怎么跟 AB PLC 建立一条以太网通讯链路」这件事的骨架给出来了。适合有 C# 基础、手上有或即将有 AB PLC、需要做数据采集或上位机监控的工程师新手能照着搭环境熟手能看清 EtherNet/IP 这条链路上哪些参数不能乱动。2. EtherNet/IP 与 CIPAB PLC 以太网通讯到底在传什么2.1 从 TCP 到 CIP三层结构别搞混很多人以为「AB PLC 以太网通讯」就是开个 TCP 连上去发字符串这是最大的误解。AB PLC 走的是 EtherNet/IP 协议它底下确实是标准以太网和 TCP/UDP但上面套了一层 CIPCommon Industrial Protocol通用工业协议。CIP 才是真正定义「你怎么读一个标签、怎么写一个值」的那一层。结构上分三段最底下是以太网物理层和 TCP/IP 协议栈中间是 EtherNet/IP 封装层Encapsulation最上面是 CIP 消息层。你发出去的每一个读写请求都要先被包成 CIP 消息再套上 EtherNet/IP 的封装头最后才走 TCP 或 UDP 发出去。这里有个关键分叉显式消息Explicit Messaging走 TCP端口 44818用来做标签读写、读 PLC 信息这类请求-应答式的操作隐式消息Implicit Messaging也叫 I/O 连接走 UDP端口 2222用来做实时 I/O 数据交换。上位机做数据采集绝大多数场景用的是显式消息也就是 TCP 44818。搞清这一点后面选库、配参数才不会跑偏。CIP 消息本身又分服务码读标签是 0x4CRead Tag Service写标签是 0x4DWrite Tag Service这些在底层库封装好之后你一般不用手写但排错时抓包看到这些码能立刻判断请求有没有发对。2.2 为什么老外例程常用 EtherNet/IP 封装库而不是自己撸 socket自己用System.Net.Sockets从零拼 CIP 报文不是不行但工作量在于封装头的会话句柄Session Handle要自己维护注册会话Register Session要先发一条特定命令每次读写还要拼 CIP 路径比如标签名要编码成 ANSI 字符串加长度前缀。老外写的例程通常直接引用一个封装库最常见的是基于 .NET 的 EtherNet/IP 库把 Register Session、Read Tag、Write Tag 都封成方法。这样做的好处是稳定坏处是你不知道底下发生了什么一旦连不上就抓瞎。我一般建议第一次接触先用封装库把链路跑通确认 PLC 侧配置没问题等要优化性能或者排查诡异断连时再回头抓包看 CIP 层。选型上如果只是读几十个标签、刷新周期 100ms 以上封装库完全够用如果要读上千点、周期 10ms 级就得考虑走隐式消息或者换更底层的实现。这份例程属于前者定位就是「把链路讲清楚」的教学型代码不要指望它扛高并发。2.3 最小可跑通的链路从 PC 到 PLC 的四个前提在写第一行 C# 之前有四个前提必须先在 PC 和 PLC 两侧确认缺一个都连不上。第一PC 和 PLC 的 IP 要在同一网段比如 PLC 是 192.168.1.10PC 就设成 192.168.1.100子网掩码一致。第二PLC 侧要在 RSLogix 5000 / Studio 5000 里确认以太网模块的 IP 已经下载进去不是只在离线工程里改了没下装。第三PC 上要装 RSLinx Classic 或者 FactoryTalk Linx用来做驱动配置和连通性验证虽然 C# 程序不直接依赖它但它是你排错时判断「是网络问题还是代码问题」的分水岭。第四防火墙要放行 44818 端口Windows 防火墙默认可能拦。验证顺序我习惯这样先在 PC 上 ping PLC 的 IP通了说明网络层没问题再打开 RSLinx用「Ethernet devices」驱动添加 PLC 的 IP能看到设备图标说明 EtherNet/IP 层通了最后才跑 C# 程序。这个顺序能把问题一层层剥开比一上来就调试代码高效得多。3. 把例程跑起来C# 侧的环境、引用与第一段读写代码3.1 环境准备与依赖引用先明确环境Visual Studio 2019 或 2022.NET Framework 4.7.2 以上老外例程很多是 Framework 项目别急着往 .NET Core 迁先跑通再说目标平台 x64 或 AnyCPU 都行。解压压缩包后通常能看到一个 .sln 和若干 .cs 文件核心逻辑集中在一个通讯类里。如果例程引用了第三方 EtherNet/IP 库先确认这个库的 DLL 在不在缺了就去 NuGet 找同名包或者按例程里的 using 命名空间反推。下面这段是我按常见封装库的用法整理的最小读写示例命名空间和类名以你实际用的库为准逻辑是通用的using System; // 假设封装库命名空间为 EthernetIP实际以例程为准 using EthernetIP; class Program { static void Main(string[] args) { // PLC 的 IP 地址必须与 PC 同网段 string plcIp 192.168.1.10; // ControlLogix 的槽号CompactLogix 通常为 0 byte slot 0; // 建立与 PLC 的会话底层会发 Register Session 命令 var plc new EthernetIPClient(plcIp, slot); plc.Connect(); // 读一个 DINT 类型标签标签名要和 Studio 5000 里完全一致 int speed plc.ReadTagint(Line1_Speed); Console.WriteLine(当前速度: speed); // 写一个 BOOL 类型标签 plc.WriteTagbool(Line1_Start, true); plc.Disconnect(); } }逻辑说明Connect()内部做的是 TCP 连接加 Register Session会话句柄在这一步拿到后续所有读写都复用这个句柄。ReadTagT里的泛型 T 决定按几个字节解析返回数据DINT 是 4 字节整型BOOL 是 1 字节。参数说明plcIp填 PLC 以太网模块的地址slot对 ControlLogix 是模块在机架上的槽位对 CompactLogix 一般是 0填错会连不上或者读到错误数据。标签名大小写敏感Line1_Speed和line1_speed在 PLC 里是两个东西。3.2 标签名、数据类型与 CIP 路径的对应关系C# 侧读标签最容易翻车的地方是标签名和数据类型对不上。AB PLC 的标签分两类控制器作用域Controller Scope和程序作用域Program Scope。控制器作用域的标签直接写名字就行程序作用域的标签要带程序名格式类似Program:MainProgram.TagName。例程里如果只演示了控制器标签你换成程序标签时忘了加前缀就会报「标签不存在」。数据类型对应关系也要记牢PLC 里的 DINT 对应 C# 的intREAL 对应floatBOOL 对应boolINT 对应shortSTRING 是结构体不能直接当string读要按自定义结构解析。数组标签读的时候要指定元素个数比如Line1_Data[10]读 10 个元素返回的是数组。这些对应关系错一个轻则数据乱码重则程序抛异常。我一般会在 Studio 5000 里先把要读的标签列个表标好名字、类型、作用域再照着写 C# 代码比边写边猜靠谱得多。3.3 用 RSLinx 验证链路再跑代码代码写好了别急着 F5。先在 RSLinx Classic 里建一个 Ethernet devices 驱动把 PLC 的 IP 加进去看能不能浏览到设备。能浏览到说明 PC 到 PLC 的 EtherNet/IP 链路是通的这时候再跑 C# 程序如果还连不上问题就在代码或库的用法上。如果 RSLinx 都连不上那跟代码没关系回去查网段、防火墙、PLC 的以太网模块配置。RSLinx 里还有个有用的功能是「RSWho」能看到整个网络的设备树。如果 PLC 在树里但 C# 连不上重点查端口 44818 有没有被占、有没有被杀毒软件拦。这一步花五分钟能省掉后面半小时的瞎调。跑通之后建议把读写周期、超时时间这些参数记下来后面做稳定性优化时是基准。4. 避坑与排查AB PLC 以太网通讯最常见的五类翻车4.1 连不上报「无法建立连接」现象程序一启动Connect()就抛异常提示连接超时或拒绝。原因通常有三个PC 和 PLC 不在同一网段PLC 的以太网模块 IP 没下装Windows 防火墙拦了 44818。解决先 ping不通就改网段ping 通但 RSLinx 也连不上回 Studio 5000 确认 IP 已下载并重启模块都通了还不行临时关防火墙测试确认后加放行规则。血泪经验是很多人改完 PLC 的 IP 忘了下装离线工程里看着是对的实际模块还是老地址。4.2 能连上但读标签报「标签不存在」现象连接成功一读标签就报错提示 Tag not found。原因标签名拼错、大小写不对、程序作用域标签没加Program:前缀、或者标签在 PLC 里根本没创建。解决在 Studio 5000 的标签监视器里复制标签名粘贴到代码里别手敲程序标签确认前缀格式确认标签已经下载到 PLC不是只在离线工程里。注意AB PLC 标签名区分大小写这是新手最容易忽略的点。4.3 读回来的数据是乱码或明显不对现象读 DINT 返回一个巨大或负得离谱的数读 REAL 返回 NaN。原因数据类型不匹配比如 PLC 里是 REALC# 按 int 解析字节序就错了或者读数组时元素个数填错把相邻标签的数据也读进来了。解决对照标签表逐个核对类型数组读取时明确元素个数REAL 类型确认库有没有做字节序转换EtherNet/IP 底层是大端C# 是小端封装库一般会处理但自己拼报文时要注意。4.4 跑一段时间后断连现象程序刚跑正常几小时或几天后连接断开重连又好了。原因PLC 侧对会话数量或空闲时间有限制长时间不通讯会被回收或者网络里有其他设备抢占带宽也可能是 PC 休眠导致网卡断开。解决加心跳定期读一个固定标签保持会话活跃设置合理的重连逻辑断连后自动重连而不是直接崩PC 侧关掉网卡节能和休眠。这个坑在长时间运行的上位机里特别常见后悔药就是一开始就把重连机制写好。4.5 写标签没反应或把 PLC 写停机现象写 BOOL 启动标签PLC 没动作或者写了一个不该写的值PLC 报故障停机。原因写标签的权限或作用域不对写入了 PLC 正在用作逻辑判断的标签造成冲突写的数据类型或范围超限。解决确认要写的标签允许外部写入关键标签在 PLC 侧做写保护或互锁写入前在代码里做范围校验。这个坑最严重调试阶段建议先在 PLC 里做好安全逻辑别让上位机随便写。5. 进阶把例程改造成能长期跑的数据采集程序5.1 批量读与订阅式采集的取舍例程演示的是单标签读写实际项目里往往要读几十上百个标签。逐个读效率低因为每次读都是一次完整的 CIP 请求-应答往返。常见做法是批量读把连续的标签放在一个数组里一次读回来再拆。AB PLC 支持读一个数组标签的多个元素如果标签本身不连续可以读一个自定义结构体UDT标签把要采集的点打包进 UDT一次读回。这样能把请求次数从上百次降到几次。再进一步是订阅式采集也就是用隐式消息建立 I/O 连接PLC 主动推数据。这种方式实时性最好但配置复杂要在 PLC 侧配置 Produced/Consumed 标签C# 侧也要支持隐式消息。我一般建议刷新周期 100ms 以上、点数几百以内批量显式读就够要到 10ms 级、点数上千再考虑隐式。别为了追求实时性一上来就上隐式调试成本高收益未必对得上。5.2 重连、超时与线程安全长期运行的程序重连逻辑是必须的。我的习惯是包一层每次读写前检查连接状态断了就重连重连失败按指数退避重试比如 1 秒、2 秒、4 秒、8 秒避免疯狂重试把 PLC 拖垮。超时时间设 3 到 5 秒太短容易误判太长卡界面。线程安全方面如果多个线程共用一个通讯对象读写要加锁或者每个线程独立连接。AB PLC 对同时建立的会话数有限制别开太多连接。// 带重连的读写封装示意 private bool EnsureConnected() { if (plc ! null plc.IsConnected) return true; // 指数退避重连最多重试 5 次 for (int i 0; i 5; i) { try { plc new EthernetIPClient(plcIp, slot); plc.Connect(); return true; } catch { // 1s, 2s, 4s, 8s, 16s System.Threading.Thread.Sleep(1000 * (int)Math.Pow(2, i)); } } return false; }逻辑说明IsConnected判断当前会话是否有效无效则重建。退避间隔用 2 的幂次增长避免网络恢复瞬间大量重连请求。参数说明重试次数 5 次是经验值网络稳定的现场可以减到 3 次网络差的可以加到 8 次但总等待时间别超过上位机的刷新周期否则界面会卡。5.3 用抓包和日志定位偶发问题偶发断连、数据跳变这类问题光看代码看不出来得靠抓包和日志。抓包用 Wireshark过滤tcp.port 44818能看到每一次 CIP 请求和应答。如果看到请求发出去了但没应答是 PLC 侧或网络问题如果应答回来了但数据不对是解析问题。日志方面把每次连接、断开、读写失败的时间点和错误码记下来出问题时按时间线对比猜快得多。我自己的习惯是任何要长期跑的采集程序上线前先挂一周日志观察有没有规律性的断连。有一次就是靠日志发现每天凌晨三点断一次最后查到是网络里另一台设备定时重启占了网关。这种问题不靠日志根本找不到。希望帮到你。本文还有配套的精品资源点击获取