本文(原文连接:OPC UA Sessions, Subscriptions and Timeouts)中,我将尽力把OPC UA通讯中的各种参数,特别是各种超时参数讲清楚。他们在控制UA 客户端与服务端连接方面很灵活,但每个参数到底起什么作用不是很清楚。

  这里我用的参数名存在于Prosys OPC UA Java SDK 的UaClient 对象,大部分参数名遵循OPC UA规范,也有部分仅与 UaClient 内部行为有关。

Sessions 会话

  所有UA 通讯都通过会话,正常情况下会话需始终活着(alive).客户端和服务端都可以监视会话的状态,以便及早发现问题,做到及时清理,即便会话没有正确关闭。

SessionTimeout 会话超时

  会话不应该很容易超时,因此1个小时是一个不错的默认值。它用来让服务器能关闭失活的会话(比SessionTimeout 更长时间没有收到客户端的任何消息),此时客户端可能已经挂了,或者不再连接。

Timeout(如服务调用超时 service call timeout)

  可以对某个服务调用使用超时,比如连接中断,或者服务器处理时间过长,10秒就ok,但服务端负载重时要延长超时,默认timeout=0表示不启用。

StatusCheckTimeout 状态检测超时

  UaClient通过StatusCheck监视与服务器的连接状态,定时从服务器获取ServerStatus,判断连接是否或者,服务器是否正常。

  你可以使用ServerStatusListener监视状态变更,或者检查ServerStatus或ServerState(ServerStatus中最有用的部分)。

  StatusCheckTimeout独立于默认的Timout,它专门用作定义状态读取的超时,如果发生超时,ServerState的值为CommunicationFault,需要自动或手动重连。

Subscriptions 订阅

  订阅用来定义要从服务器获取的数据,订阅与会话是松耦合的,如果会话超时,订阅可以转给新会话,由UaClient自动完成,可以用几个参数控制订阅。

  最重要的参数是PublishingInterval和SamplingInterval,用来定义数据采样周期,还有定义订阅状态监视的参数。

PublishingInterval 发布周期

  发布周期定义服务端多长时间检查一次订阅是否有新数据需要发给客户端,通常1000毫秒,不应该为-1或0.

  与其使用很小的发布周期,不如使用更小的采样周期。服务端有可能限制最小发布周期。

SamplingInterval 采样周期 和 QueueSize 队列长度

如果想要比发布周期更快记录数据,可以使用采样周期,同时要增加队列长度,这样服务端能够缓存所有数据样本,到发布周期时一次性发给客户端。

KeepAliveCount 保活计数

  如果到发布周期但没有新数据,服务端会跳过但保活次数定义了最多可以跳过多少次,之后哪怕是空消息也要发给客户端,告诉客户的订阅仍然有效,但没数据。

LifeTimeCount 寿命计数

  客户端有责任向服务端发送订阅请求,然后服务端才能发送数据变更通知。服务端通过判断是否有新的请求来判断客户端是否活着。LifeTimeCount定义新请求之前最多允许多少个发布周期,超过后服务端判定客户端失活,清除订阅。

Republish 重发

  通知消息有序号,UaClient可以检测是否有漏掉的消息,如果有,可以发送重发请求让服务端把漏掉的消息再补发,这就要求服务端保存需发送的消息,直到客户端确认收到为止。

提高性能(8月28日新增)

  使用 UA-.NETStandard 开发 OPCUA 客户端时,有两种回调方式,一是给每个 MonitoredItem 的Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args) 事件加上回调,访问args里面的 NotificationValue属性(MonitoredItemNotification类型)。当订阅数万点时,内存开销会很大,性能不佳。

  在订阅点很多时,推荐使用Subscription上的FastDataChangeCallback 回调来批量获取数据变更的点,仍然能够得到MonitoredItem 和 MonitoredItemNotitfication 两个对象,如下代码中的callback是外部传入的Action。

m_subscription.FastDataChangeCallback = (Subscription subscription, DataChangeNotification notification, IList<string> stringTable) =>
{
	foreach (MonitoredItemNotification itemNotification in notification.MonitoredItems)
	{
		try
		{
			MonitoredItem monitoredItem = subscription.FindItemByClientHandle(itemNotification.ClientHandle); 
			if (monitoredItem == null)
			{
				continue;
			}
			callback(monitoredItem, itemNotification);
		}
		catch (Exception exception)
		{
			Logger.Error(exception, "FastDataChangeCallback 出错", LogSource);
		}
	}
};

丢失订阅问题(待解)

  在项目上使用时遇到个别点数据十几天不刷新,用opcclient测试数据是变的,可能跟参数设置不合理有关。

  PublishingInterval 之前设置为1000,即1秒发布一次,似乎太长了,如果Subscription下的订阅点多,1秒1次要发布的数据可能造成积压,根据网络情况可缩短发布周期,我在局域网改用100ms。

  MaxNotificationsPerPublish 一次发布点数上限,这个参数应与PublishingInterval结合起来,我理解二者的乘积应≥订阅点数*SamplingInterval,才能确保所有数据都能发布出去。

  重复订阅的尝试。 跟踪每个点数据的最后变化时间,当数据不变超过规定时限(如24hr),重新订阅该点。测试发现,90%以上的点都要重新订阅,不知道是不是我连的OPC Server数据变化慢的原因。另外,重新订阅逻辑需要维护点与其对应的Subscription.Key,使得代码逻辑变得复杂。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐