news 2026/9/15 3:00:41

OPC UA通信实例:PLC与PC机数据交互的C#实现与调优

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OPC UA通信实例:PLC与PC机数据交互的C#实现与调优

简介:面向工业自动化中PLC与上位机之间的数据交换,提供一套完整的OPC UA通信实例源码,适合PLC工程师、工控软件开发人员及需要深入理解OPC UA协议栈的进阶学习者,可借此快速搭建服务器与客户端的通信框架,从而降低工业通信项目的开发门槛。资源共285个文件,压缩包大小仅926KB,源码以C语言和C++程序文件为主,另含Python辅助脚本、CMake构建配置、Shell部署脚本、Markdown说明文档等,目录分明,便于定位服务器端、客户端及安全配置模块,兼顾可读性与工程实用性。已有263人学习下载,代码覆盖OPC UA的核心机制,包括信息模型节点组织、身份验证与加密、读写与订阅服务、二进制编码传输等,并配套示例应用展示完整的交互流程,帮助开发者快速理解关键实现。通过学习,可理解从服务器建模、监听请求到客户端浏览读写、订阅推送的完整通信链路,为实际项目集成或二次开发提供直接可用的工程参考。

1. OPC UA 通信在 PLC 与 PC 机之间到底解决什么问题

车间里最不缺的就是各种协议。老式 PLC 要往 PC 机传数据,常见做法是组态软件做变量映射,或者写底层 Socket 去解析私有协议;换一台 PLC 型号,解析代码就要重来一遍。OPC UA 的出现把设备与上位机之间的数据通道标准化成以太网服务:PLC 侧要么内置服务器,要么通过网关把地址空间暴露出来;PC 机侧只用统一的 OPC UA 客户端库,就能读状态、写指令、订阅变化。标题里“实例源码”多数是指 PC 机客户端这部分,以及与之对应的 PLC 服务器配置。对做设备数据采集、MES 对接、上位机开发的工程师来说,这个标题实际能拆成三件事:连接怎么建立、节点怎么定、读写和订阅怎么落地。

2. PLC 与 PC 机通信前先准备好 OPC UA 服务器端点与网络连接

2.1 PLC 侧内置 OPC UA 服务器已经是最省事的接法

现在的 PLC 侧支持 OPC UA 通信的路径有好几条。最省事的是使用 PLC 内置的 OPC UA 服务器,比如西门子 S7-1200/1500 在博途项目中可以勾选激活 OPC UA 服务器,CPU 固件本身就会监听 4840 端口;三菱、汇川等品牌对 OPC UA 的支持也在逐步覆盖,不支持时通常借助协议转换网关。内置服务器的好处是少一台中间硬件,PLC 的 DB 块、I/Q 地址会被映射成 OPC UA 服务器地址空间中的节点,PC 机客户端不需要安装 PLC 私有驱动,直接走标准协议。

无论内置还是网关,PC 机和 PLC 之间第一步是网络层能通。PLC 一般固定占用一个工程网口,IP 通常为 192.168.1.x,PC 机网卡要设在同一个网段,例如 PLC 为 192.168.1.10,PC 机为 192.168.1.20,掩码统一 255.255.255.0。如果用虚拟机跑客户端,网络连接模式建议选桥接而不是 NAT,桥接能让 PLC 的回包直接发到宿主机的物理网卡,NAT 模式在部分工业网段里会出现 ARP 不同、PLC 端回包错路的现象。这里说的网络连接模式,指 VMware 或 VirtualBox 给虚拟机网卡分配 IP 的方式,桥接模式下 PC 机虚拟机可以拿到和 PLC 同一子网的 IP。

2.2 OPC UA 客户端连接地址和最小连接代码

PC 机侧 OPC UA 客户端以库的形式接入。C# 常见做法是拿 OPC Foundation 的 UA-.NETStandard 库,C++ 用 open62541,Python 可以用 asyncua。连接地址统一写成opc.tcp://192.168.1.10:4840,这是 UA 的标准格式,不需要额外指定协议厂商标识。很多 OPC UA 客户端库还会要求一个 ApplicationName,服务器会拿这个名称来区分是哪台 PC 发起的连接。

C# 的最小连接代码如下,省掉证书细节,先把会话建起来:

using Opc.Ua; using Opc.Ua.Client; using Opc.Ua.Configuration; var config = new ApplicationConfiguration { ApplicationName = "PCClient", ApplicationType = ApplicationType.Client, SecurityConfiguration = new SecurityConfiguration { // 演示环境先自动接受不受信任的证书,生产环境必须删除这一行 AutoAcceptUntrustedCertificates = true, RejectSha1SignedCertificates = false }, TransportQuotas = new TransportQuotas { OperationTimeout = 15000 } }; // useSecurity=false 表示先用无加密策略把连接跑通 var endpoint = CoreClientUtils.SelectEndpoint( config, "opc.tcp://192.168.1.10:4840", useSecurity: false); using (var session = Session.Create(config, endpoint, true, true, "pc-session").Result) { Console.WriteLine("连接成功: " + session.Endpoint.EndpointUrl); }

逻辑说明:ApplicationConfiguration是每个 OPC UA 客户端启动前都要准备的配置文件,包含应用名、证书、传输配额。CoreClientUtils.SelectEndpoint会先尝试连接服务器并读取它声明的支持的安全策略列表,useSecurity: false表示选择SecurityPolicy.None这一条,适合现场调试。Session.Create的参数里,第三个updateBeforeConnect为 true 时会在创建会话前重新获取端点,第四个checkDomain为 true 时跳过证书域名校验,IP 直连 PLC 时这句很关键,否则可能出现域名不匹配的异常。OperationTimeout是单个请求的等待时间,PLC 侧响应慢时调到 30000 毫秒更稳妥。

连接参数可以直接做成配置项,建一个表格方便对接时快速核对。

参数常见值说明
EndpointUrlopc.tcp://192.168.1.10:4840PLC 侧 OPC UA 服务器地址,内置服务器默认 4840
SecurityPolicyNone / Basic256Sha256演示先用 None,正式环境使用加密策略
OperationTimeout15000 msPC 机客户端请求超时,PLC 响应慢要调大
ApplicationNamePCClient会出现在 PLC 服务器的会话列表里
checkDomaintrueIP 直连时跳过证书域名校验

2.3 节点地址不是猜出来的

连接建立后,读写的是 PLC 地址空间里的节点。节点地址由命名空间和标识符组成,例如ns=2;s=DB1_Tempns=2是命名空间索引 2,不同 PLC 品牌把 DB 块字段放在不同的命名空间后面;s=DB1_Temp是字符串标识符,表示 PLC 程序里的变量。节点 ID 的准确写法必须通过 OPC UA 客户端工具浏览地址空间得到,常见工具是 UA Expert,输入上面的连接地址,连上后就能看到 PLC 暴露出来的所有 DB、I/Q 地址和它们的类型。不要凭记忆拼节点 ID,尤其是西门子 DB 块,在 PLC 侧还需要把对应 DB 块的“OPC UA 访问权限”打开,否则节点在服务器侧不会公布。

3. PC 机侧 OPC UA 实例源码:读实时值、写点与订阅数据变化

3.1 批量读取多个节点,一次往返拿到一整组数据

PC 机与 PLC 通信最常用的是读操作。逐点调用ReadValue会要求每个点做一次请求,PLC 地址空间大的时候 PC 机 CPU 占用率很高。常见做法是用ReadValues把多个 NodeId 打包在一个请求里,OPC UA 服务器端也会尽量顺序执行,整体延迟比逐点读低不少。

var nodeIds = new NodeIdCollection { new NodeId("ns=2;s=DB1_Temp"), new NodeId("ns=2;s=DB1_Pressure"), new NodeId("ns=2;s=DB1_Speed") }; var readValues = session.ReadValues(nodeIds, 0, TimestampsToReturn.Both); for (int i = 0; i < readValues.Count; i++) { Console.WriteLine($"{nodeIds[i]} => {readValues[i].Value} | {readValues[i].StatusCode}"); }

逻辑说明:ReadValues第一个参数是要读的节点集合,第二个参数 0 表示取最近的值,第三个参数TimestampsToReturn.Both表示同时返回来源时间戳和服务器时间戳,方便 PC 机侧判断数据是否长时间未更新。返回列表和请求节点顺序一一对应,循环时按索引取数据。StatusCode用于判断单个节点读取失败,比如某个节点地址写错,不会影响同批次其它节点成功返回。

3.2 写操作:布尔点、整数点、浮点点的类型对齐

PC 机向 PLC 写入启动命令、设定值,是 PLC 控制逻辑要求最严的一部分。写操作必须保证 NodeId 准确,并且值类型和 PLC 侧变量类型一致;常见坑是 PLC 侧是REAL,PC 侧写了个int,服务器会直接返回BadTypeMismatch

var writeCollection = new WriteValueCollection { new WriteValue { NodeId = new NodeId("ns=2;s=DB1_StartBtn"), AttributeId = Attributes.Value, Value = new DataValue(true) { SourceTimestamp = DateTime.UtcNow, ServerTimestamp = DateTime.UtcNow } }, new WriteValue { NodeId = new NodeId("ns=2;s=DB1_SpeedSet"), AttributeId = Attributes.Value, Value = new DataValue(30.0f) } }; session.Write(writeCollection, out var results); foreach (var r in results) { Console.WriteLine(r.Code); }

逻辑说明:WriteValueAttributeId固定是Attributes.ValueDataValue里不光放值,还可以带时间戳。写入布尔点时 PLC 侧一般映射为 BIT 或 BOOL,用true/false;浮点最好显式写成30.0f,不要写成30,避免 C# 编译成 double 后 OPC UA 栈把类型识别成双精度,而 PLC 变量是单精度 REAL。写的结果列表和请求集合顺序一致,拿到Good才算成功;如果返回BadNotWritable,先检查 PLC 服务器账户的写权限,而不是怀疑代码。

3.3 订阅数据变化:按周期推送,比轮询更省网络带宽

OPC UA 相对传统 Socket 通信的明显优势是订阅。PC 机不需要每秒向 PLC 轮询,而是告诉服务器“我关注这几个节点,有变化再推给我”。订阅由SubscriptionMonitoredItem组成,一个订阅可以挂多个监控项,服务器按发布周期批量推送。

var subscription = new Subscription(session.DefaultSubscription) { PublishingInterval = 100, KeepAliveCount = 10, LifetimeCount = 100 }; session.AddSubscription(subscription); subscription.Create(); var monitoredItem = new MonitoredItem { StartNodeId = new NodeId("ns=2;s=DB1_Temp"), AttributeId = Attributes.Value, SamplingInterval = 100, QueueSize = 10, DiscardOldest = true }; monitoredItem.Notification += (MonitoredItem sender, MonitoredItemNotificationEventArgs e) => { var dataValue = sender.LastValue; Console.WriteLine($"温度值: {dataValue.WrappedValue.Value}"); }; subscription.AddItem(monitoredItem); subscription.ApplyChanges();

逻辑说明:PublishingInterval是服务器向 PC 机客户端推送数据的周期,单位毫秒,100 毫秒意味着最多每秒推送 10 次;SamplingInterval是 PLC 侧采样节点的间隔,它决定了服务器多久检查一次节点变化。两者不相等的时候,数据是否真的推送还取决于节点值变化和发布周期。QueueSize=10表示服务器在客户端处理不及时的时候缓存最多 10 个变化值,DiscardOldest=true表示趁旧保新,适合温度、压力这种只关心当前值的过程量。Notification事件在客户端收到推送时触发,事件处理器里直接从sender.LastValue取最新值,不需要再主动读一次 PLC。

表格总结三个操作的关键 API:

操作API关键参数
批量读session.ReadValues(ids, 0, ts)第三个参数设置时间戳返回策略
session.Write(items, out results)Value必须和 PLC 变量类型一致
订阅Subscription+MonitoredItemPublishingInterval 与 SamplingInterval 分开设

4. 实例源码连通性排查与参数调优:端点、证书、采样间隔

4.1 先分清网络不通还是协议不通

写完了连接、读写、订阅代码,剩下的工作就是排坑。最常见的第一道坑是 PC 机 ping 不通 PLC。在 PC 机上先做端口探测,确认 4840 真的在监听:

# Windows PowerShell Test-NetConnection 192.168.1.10 -Port 4840

如果显示TcpTestSucceeded: False,问题在网络层,检查 PLC 是否启用了 OPC UA 服务器、防火墙是否放行,Windows 还得注意专用网络与公用网络的文件共享策略。如果端口能通但客户端报BadTimeout或握手错误,才进入协议层排查。用 UA Expert 工具直接连同一个地址,能连上就说明 PC 机代码库版本和服务器不兼容的概率很小,问题出在客户端配置。

排查表可以覆盖绝大多数现场情况:

现象原因处理办法
端口测试失败PLC 侧服务器未启动 / 防火墙检查 PLC 项目是否激活 OPC UA;放行 4840
BadSecurityChecksFailed客户端证书不被服务器信任把客户端证书发到 PLC 服务器信任列表,或临时 AutoAccept
BadNodeIdUnknown节点 ID 拼错用 UA Expert 浏览地址空间复制节点
BadSessionIdInvalid会话被服务器关闭增大 KeepAliveCount,或客户端做了长连接重连
数据读到 null节点类型映射错误用 UA Expert 查看节点 DataType,再改 C# 类型

4.2 证书与安全策略的正确配置顺序

OPC UA 服务器在 PLC 侧只监听一个端口,但访问控制由安全策略加用户认证两层决定。PC 机客户端第一次连接时,库会生成本机证书;服务器默认不接受陌生证书,所以会出现BadSecurityChecksFailed。测试期最省事的做法是把AutoAcceptUntrustedCertificates设为 true,让它自动信任服务器端证书。这个开关只能用于内网演示,一旦接入产线,PLC 侧的安全审计就会把它拒掉,因此生产环境要把客户端证书导出后添加到 PLC 服务器的信任列表。不同 PLC 的添加界面不一样,但原理都是“服务器端信任客户端,客户端信任服务器”。

安全策略的选择顺序:老式 PLC 或网关只支持Basic256,新设备基本支持Basic256Sha256,更强的是Aes128_Sha256_RsaOaep。能支持时优先用Basic256Sha256。如果客户端代码里设了useSecurity: true但服务器不支持对应策略,SelectEndpoint会返回一个不支持的 endpoint 然后握手失败;反过来把安全策略设成 None 就可以通。这说明不是代码逻辑错,而是两端策略不匹配。

4.3 采样间隔和发布间隔不是越小越好

订阅参数调优是 OPC UA 通信实例源码里最容易被人忽略的部分。把PublishingInterval调到 10 毫秒,PC 机端每秒要处理 100 个包,PLC 侧 CPU 也承受不住。实际参数至少参考三个因素:PLC 扫描周期、数据变化速度、PC 机数据显示需求。

给出一个经验参考表:

场景SamplingIntervalPublishingIntervalQueueSize
电机转速监控50 ms100 ms5
模拟量温度采集500 ms1000 ms10
状态机变化100 ms100 ms10
打开调试日志20 ms50 ms50

还有一个容易踩的坑:SamplingInterval设得比 PLC 实际扫描周期还短,服务器会按自己能力返回值,不会报错,但 PC 机端可能以为数据是每 10 毫秒刷新一次,实际上 PLC 扫描一遍就要几十毫秒。调试时可以打上数据的时间戳看真实间隔。订阅对象要长期持有,方法退出就被 GC 回收的话,订阅会静默断开,等下一次发布超时才会发现。

5. 把 OPC UA 实例源码扩展成控制场景的高级用法

5.1 用结构化节点一次读回整块 DB 数据

PLC 侧程序里一旦有几十个温度、压力、状态信号,逐个读写节点会让代码变得又长又难维护。常见做法是在 PLC 内把这些信号放进同一个 DB 块,然后让 OPC UA 服务器把这个 DB 块暴露成一个结构化节点。PC 机端只需要读这一个 NodeId,就能拿回一个带有多个字段的结构体,网络往返次数从几十次降低到一次。

var dbNode = new NodeId("ns=2;s=DB1_DataBlock"); DataValue dv = session.ReadValue(dbNode); if (dv.Value is ExtensionObject ext && ext.Body != null) { Console.WriteLine(ext.Body); }

说明:ExtensionObject是 OPC UA 表示复杂结构体的一种数据类型,具体字段顺序要在客户端侧按 PLC 定义的结构体反序列化。西门子 PLC 的 OPC UA 服务器会把整个 DB 的结构暴露出来,如果发现读取结果是 null,多数是因为服务器没有把这个 DB 设置为可访问。

5.2 用方法调用代替裸写,把互锁放到 PLC 侧

面向控制场景时,PC 机直接写“启动”位是不推荐的做法。更可靠的方法是 PLC 里定义好 OPC UA 方法,例如StartPumpStopAlarm,PC 机调用方法而不是写变量。调用时所有互锁条件在 PLC 内判断,返回一个结果码,PC 机再根据结果码显示成败原因。这样即使 PC 机键盘误触发,PLC 扫描周期内也会首先执行安全条件。实例源码里这一块往往只体现客户端调用,真正的实现细节在 PLC 侧方法块里。

5.3 用 Reconnect 保证断线后自动恢复

长连的 OPC UA 会话会因 PLC 重启、网线松脱而断开,PC 机程序需要监听SessionReconnect事件并重新建立订阅。常见做法是维护一个已订阅节点集合,断线重连成功后把这些监控项重新加回去。注意重新订阅后的第一帧数据通常需要等一个发布周期,控制程序里要做超时判断,不要误以为订阅已经失效。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 2:59:33

AI写代码时代,程序员如何重塑核心竞争力?

上周我让AI帮忙排查一个线上偶发队列堆积的问题&#xff0c;它一口气给了五个方向&#xff0c;我照着试了三个&#xff0c;都是错的&#xff0c;第四个试起来成本太高&#xff0c;第五个其实是我自己想到的。同一周&#xff0c;我的一个同事用AI把部门内部的一个数据清洗工具从…

作者头像 李华
网站建设 2026/9/15 2:58:37

三河网站建设-七天网络怎么选?对比5家技术栈不踩坑

三河网站建设-七天网络怎么选?对比5家技术栈不踩坑 找建站公司最怕啥?就是报价单上写着“全能套餐”,结果做出来的站慢得像蜗牛,还没法改。很多三河的老老板跟我吐槽,花了几千块找“七大”或者“七大”那种公司,最后发现服务器在境外,备案都办不下来,或者代码是一坨屎,想换个图片都得求着开发。…

作者头像 李华
网站建设 2026/9/15 2:58:02

热搜词背后的软件测试行业真相:从面试题到AI测试的应对之道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 2:57:50

毕夏AI官网:数据分析的“翻译官”逻辑

毕夏AI官网 www.bixiaai.com 毕夏AI写作官网 www.bixiaai.com 毕夏官网 www.bixiaai.com 毕夏智能写作官网 www.bixiaai.com 毕夏AI官网 www.bixiaai.com 微信公众号搜一搜&#xff1a;毕夏AI官网 做论文写作科普久了&#xff0c;我发现一个很有意思的现象&#xff1a;大…

作者头像 李华
网站建设 2026/9/15 2:57:46

开题报告写不出来,不是你笨,是没人告诉你它到底在考什么

毕夏AI官网 www.bixiaai.com 毕夏AI写作官网 www.bixiaai.com 毕夏官网 www.bixiaai.com 毕夏智能写作官网 www.bixiaai.com 带过几届学生之后&#xff0c;我发现一个规律&#xff1a;论文写不下去的人&#xff0c;多半不是卡在正文&#xff0c;而是卡在开题报告。 开题…

作者头像 李华
网站建设 2026/9/15 2:57:18

Flipper Zero 固件内嵌 Mbed TLS 的安全策略与威胁模型全解析

Flipper Zero 固件内嵌 Mbed TLS 的安全策略与威胁模型全解析 【免费下载链接】flipperzero-firmware Flipper Zero firmware source code 项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware 导读 本文以 Flipper Zero 固件仓库中随 OpenThread …

作者头像 李华