OPC UA 统一架构) (二)
OPC UA (二)
重头戏,捞取数据,才是该干的事。想获取数据,先有数据源DataPrivade,DataPrivade的数据集合不能和BaseDataVariableState的集合存储同一地址,或者称为浅副本
需要提出下面类重新设计,按照自己的idea来做
public class ReferenceNodeManager : CustomNodeManager2
UA-.NETStandard设计的数据锁效果好,点数一多,多Client就比较卡。后来发现是Lock问题,Lock时间一长,其他Client就只能等待,目前想到的解决办法就是深拷贝数据,尽量缩短取值时间。就是上述说的不是同一片内存空间。Server的数据和DataPrivade数据不是同一个。
private BaseDataVariableState CreateVariable(NodeState parent, string path, string name, NodeId dataType, int valueRank)
{
BaseDataVariableState variable = new BaseDataVariableState(parent); variable.SymbolicName = name;
variable.ReferenceTypeId = ReferenceTypes.Organizes;
variable.TypeDefinitionId = VariableTypeIds.BaseDataVariableType;
variable.NodeId = new NodeId(path, NamespaceIndex);
variable.BrowseName = new QualifiedName(path, NamespaceIndex);
variable.DisplayName = new LocalizedText("en", name);
variable.WriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
variable.UserWriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
variable.DataType = dataType;
variable.ValueRank = valueRank;
variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
variable.Historizing = false;
variable.Value = GetNewValue(variable);
variable.StatusCode = StatusCodes.Good;
variable.Timestamp = DateTime.UtcNow;
四、DataPrivade
a) BaseDataVariableState 的属性
SymbolicName: A symbolic name for the node that is not expected to be globally unique.(节点的符号名,不应是全局唯一的。)(百度翻译)
NodeId:The identifier for the node.(节点的标识符)
BrowseName:The browse name of the node.(节点的浏览名称)
DisplayName:The display name for the node.(节点的显示名称)
DataType:The data type for the variable value.(变量值的数据类型)
ValueRank:The number of array dimensions permitted for the variable value.(变量值允许的数组维数)
Value:The value of the variable.(变量的值)(变量:或者称为节点)
个人认为上面属性比较重要,加黑字体的是用到的,其他暂时没用到。
b) 数据存储在不同区域,下面定义
可能有的用到,有的没用到
1 #region Read
2 // Real BaseDataVariableState
3 public Dictionary<string, BaseDataVariableState> BaseDataVariableStateDic = new Dictionary<string, BaseDataVariableState>();
4 // temp BaseDataVariableState
5 public Dictionary<string, BaseDataVariableState> BaseDataVariableStateTempDic = new Dictionary<string, BaseDataVariableState>();
6
7 // for example ***_***_*** ,OPC
8 private readonly Dictionary<string, String> baseDataVariableToXXXXDic = new Dictionary<string, String>();
9 // for example ***.***.*** ,IOServer
10 private Dictionary<string, String> XXXXToBaseDataVariableDic = new Dictionary<string, String>();
11 #endregion
12
13 #region Write
14 private List<InterfaceSample.Model.ValueItem> writeDataList = new List<InterfaceSample.Model.ValueItem>();
15 private Dictionary<string, BaseDataVariableState> baseDataVariableDicWrite = new Dictionary<string, BaseDataVariableState>();
16 #endregion
17
18 public InterfaceSample.OPCUADataProvide OpcuaDataPrivade = null;
19
20 private object _obj = new object();
21 #endregion
c) 获取与设置数据Value
1. 定时器更新数据,不要因为数据太多卡住,多次增加线程,争抢资源。放在了CreateAddressSpace里,在OPC UA(一)可以看到。Timer:System.Threading.Timer。
1 m_simulationTimer = new Timer(DoSimulation, cts, 1000, 1000);
2
回调DoSimulation(TimerCallback),cts(CancellationTokenSource cts)后面解释,DoSimulation里要使用Change,至于为什么需要自己查,不怎么用,用的不好。
1 private void DoSimulation(object state)
2 {
3 try
4 {
5 #region CancellationTokenSource
6 var source = state as CancellationTokenSource;
7
8 if (source == null || cts == null)
9 {
10 return;
11 }
12 if (source.Token.IsCancellationRequested && cts.Token.IsCancellationRequested)
13 {
14 return;
15 }
16 else
17 {
18 if (!cts.Token.IsCancellationRequested)
19 {
20 source = cts;
21 }
22 }
23 #endregion
24
25 if (m_dynamicNodes_temp == null)
26 {
27 return;
28 }
29 m_simulationTimer.Change(0, Timeout.Infinite);
30
31 #region
32 lock (_obj)
33 {
34 string[] strs = new string[baseDataVariableToRTDBDic.Count];
35 baseDataVariableToRTDBDic.Values.CopyTo(strs, 0);
36 List<string> li = new List<string>();
37 foreach (var str in strs)
38 {
39 if (source.Token.IsCancellationRequested)
40 {
41 m_simulationTimer.Change(1000, 1000);
42 return;
43 }
44 li.Add(str);
45 }
46 var obsli = OpcuaDataPrivade.GetItemDatas(li);
47
48 if (obsli == null)
49 {
50 m_simulationTimer.Change(1000, 1000);
51 return;
52 }
53 for (int i = 0; i < obsli.Count; i++)
54 {
55 if (source.Token.IsCancellationRequested)
56 {
57 m_simulationTimer.Change(900, 1000);
58 return;
59 }
60 m_dynamicNodes_temp[i].Value = obsli[i];
61 }
62 }
63
64 #endregion
65
66 lock (Lock)
67 {
68 int count = 0;
69 foreach (BaseDataVariableState variable in m_dynamicNodes_temp)
70 {
71 if (source.Token.IsCancellationRequested)
72 {
73 m_simulationTimer.Change(900, 1000);
74 return;
75 }
76 77 if (BaseDataVariableStateDic.ContainsKey(variable.NodeId.Identifier.ToString()))
78 {
79 m_dynamicNodes[count].Value = variable.Value;
80 m_dynamicNodes[count].Timestamp = DateTime.UtcNow;
81 m_dynamicNodes[count].ClearChangeMasks(SystemContext, false);
82 ++count;
83
84 }
85 }
86 m_simulationTimer.Change(1000, 1000);
87 //m_simulationTimer = new Timer(DoSimulation, null, 1000, 1000);
88 }
89 }
90 catch (Exception e)
91 {
92 Utils.Trace(e, "Unexpected error doing simulation.");
93 }
94 }
2. 一般地,Client用户端对Value的赋值(输入)在优先级上要高于读取,所以CancellationTokenSource的用处体现在这。
UA-.NETStandard里的BaseDataVariableState的Write集合,自己设计的,里面能到什么OnWrite或Write之类的,直接把CustomNodeManager2的Write直接拿过来
public override void Write( OperationContext context,IList<WriteValue> nodesToWrite,IList<ServiceResult> errors)
不整段代码,贴插入部分,里面有前后,找的话会找到,(override不一定成功,呵)
1 CheckIfSemanticsHaveChanged(systemContext, propertyState, propertyValue, previousPropertyValue);
2 }
3 var baseNode = handle.Node as BaseDataVariableState;
4 if(baseNode != null) nodesToWriteList.Add(baseNode);
5
6 handle.Node.ClearChangeMasks(systemContext, false);
7
8 }
9
10 // check for nothing to do.
11 if (nodesToValidate.Count == 0)
12 {
13 return;
14 }
另外的代码,遥相呼应一下,OPC UA(一) 里的CreateAddressSpace里的Task。
1 public void WriteProcHandle(CancellationTokenSource source)
2 {
3 //CancellationTokenSource source = new CancellationTokenSource();
4
5 while (true)
6 {
7 Thread.Sleep(500);
8 try
9 {
10 #region
11 lock (Lock)
12 {
13 if (baseDataVariableDicWrite.Count > 0)
14 {
15 foreach (var item in baseDataVariableDicWrite)
16 {
17 writeDataList.Add(new InterfaceSample.Model.ValueItem() { Key = baseDataVariableToRTDBDic[item.Key], Value = item.Value.Value });
18 }
19
20 baseDataVariableDicWrite.Clear();
21 }
22 }
23
24 lock (_obj)
25 {
26 if (writeDataList.Count <= 0)
27 {
28 continue;
29 }
30
31 source.Cancel();
32 List<string> keys = new List<string>();
33 List<object> values = new List<object>();
34 foreach (var item in writeDataList)
35 {
36 keys.Add(item.Key);
37 values.Add(item.Value);
38 }
39
40 if (writeDataList.Count > 0)
41 {
42 OpcuaDataPrivade.SetItemDatas(keys, values);
43 writeDataList.Clear();
44 cts = new CancellationTokenSource();
45 }
46
47 }
48
49 #endregion
50
51 }
52 catch (Exception)
53 {
54 //source = new CancellationTokenSource();
55 }
56 finally
57 {
58 if (cts.Token.IsCancellationRequested)
59 {
60 cts = new CancellationTokenSource();
61 }
62 }
63 }
64 }
大概就是这样。
OPC UA 统一架构) (二)的更多相关文章
- OPC UA 统一架构) (一)
OPC UA 一 .OPC UA简介 OPC UA(OPC Unified Architecture)是下一代OPC统一体系架构,是一种基于服务的.跨越平台的解决方案. OPC UA具有如下特点: 1 ...
- OPC UA (统一架构)的优势
OPC UA OPC统一架构(OPC Unified Architecture)是OPC基金会(OPC Foundation)创建的新技术,更加安全.可靠.中性(与供应商无关),为制造现场到生产计划或 ...
- OPC UA
OPC UA将来自不同厂商不同设备的数据进行统一格式.统一显示. OPC: originally knowns as “OLE for Process Control”, now “Open Plat ...
- OPC协议解析-OPC UA OPC统一架构
1 什么是OPC UA 为了应对标准化和跨平台的趋势,为了更好的推广OPC,OPC基金会近些年在之前OPC成功应用的基础上推出了一个新的OPC标准-OPC UA.OPC UA接口协议包含了之前的 ...
- 转:OPC协议解析-OPC UA OPC统一架构
1 什么是OPC UA 为了应对标准化和跨平台的趋势,为了更好的推广OPC,OPC基金会近些年在之前OPC成功应用的基础上推出了一个新的OPC标准-OPC UA.OPC UA接口协议包含了之前的 ...
- SharpNodeSettings项目,可配置的数据采集,统一的工业数据网关,OPC UA服务器开发,PLC数据发布到自身内存,redis,opc ua,以及数据可视化开发
本项目隶属于 HslCommunication 项目的SDK套件,如果不清楚HslCommunication组件的话,可以先了解那个项目,源代码地址:https://github.com/dathli ...
- C# 读写opc ua服务器,浏览所有节点,读写节点,读历史数据,调用方法,订阅,批量订阅操作
OPC UA简介 OPC是应用于工业通信的,在windows环境的下一种通讯技术,原有的通信技术难以满足日益复杂的环境,在可扩展性,安全性,跨平台性方面的不足日益明显,所以OPC基金会在几年前提出了面 ...
- C# 实现opc ua服务器的远程连接(转)
原文转自:https://www.cnblogs.com/dathlin/p/7724834.html OPC UA简介 OPC是应用于工业通信的,在windows环境的下一种通讯技术,原有的通信技术 ...
- 从 OPC 到 OPC UA
[前言]OPC是一个工业标准,所属国际组织是OPC基金会,现有会员已超过220家,包括世界上所有主要的自动化控制系统.仪器仪表及过程控制系统的公司. [经典 OPC]经典OPC规范基于微软Window ...
随机推荐
- Elasticsearch索引生命周期管理方案
一.前言 在 Elasticsearch 的日常中,有很多如存储 系统日志.行为数据等方面的应用场景,这些场景的特点是数据量非常大,并且随着时间的增长 索引 的数量也会持续增长,然而这些场景基本上只有 ...
- 码农英语四级考了6次,也能进知名IT外企
程序员学英语 这显然不是新鲜的话题,但再怎么重复强调都不过分! 为啥要学 IT是当今世界发展最快的行业,没有之一!作为其中的从业人员,要始终保持对最新技术的关注度,难免需要阅读英文新闻或文章 平时工作 ...
- 初始MQTT
初识 MQTT 物联网 (IoT) 设备必须连接互联网.通过连接到互联网,设备就能相互协作,以及与后端服务协同工作.互联网的基础网络协议是 TCP/IP.MQTT(消息队列遥测传输) 是基于 TC ...
- mapboxgl实现带箭头轨迹线
最近在使用mapboxgl实现轨迹展示时,想实现类似高德地图导航轨迹效果,然而并未在网上找到类似示例.经一番研究与尝试,最终解决,效果如下. 添加箭头核心代码如下,只需在配置layout中添加symb ...
- mysql词法分析和语法分析
如果没有命中查询缓存,就要开始真正执行语句了.首先,MySQL 需要知道你要做什么,因此需要对 SQL 语句做解析.分析器先会做"词法分析".你输入的是由多个字符串和空格组成的一条 ...
- MySQL不会丢失数据的秘密,就藏在它的 7种日志里
本文收录在 GitHub 地址 https://github.com/chengxy-nds/Springboot-Notebook 进入正题前先简单看看MySQL的逻辑架构,相信我用的着. MySQ ...
- Linux系统性能排查
一.性能监控Sar命令 语法格式: [root@cdh init.d]# sar -h -A:所有报告的总和 -b:显示I/O和传递速率的统计信息 -B:显示换页状态 -d:输出每一块磁盘的使用信息 ...
- hive之Json解析(普通Json和Json数组)
一.数据准备 现准备原始json数据(test.json)如下: {"movie":"1193","rate":"5", ...
- 线程安全问题synchronized锁
1.线程安全问题的原因 因为 Java 中对静态变量的自增,自减并不是原子操作,要彻底理解,必须从字节码来进行分析 例如对于 i++ 而言(i 为静态变量),实际会产生如下的 JVM 字节码指令: ...
- Spring(3) --事务,隔离级别,设计模式
什么是事务?事物的四大特性? 事务是指单个逻辑工作单元执行的一系列操作(ACID),这些操作要么全部执行,要么全部不执行,是不可中断的. (1)原子性(Atomicity)是指事务所有操作是不可中断的 ...