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 ...
随机推荐
- [LeetCode]501. Find Mode in Binary Search Tree二叉搜索树寻找众数
这次是二叉搜索树的遍历 感觉只要和二叉搜索树的题目,都要用到一个重要性质: 中序遍历二叉搜索树的结果是一个递增序列: 而且要注意,在递归遍历树的时候,有些参数如果是要随递归不断更新(也就是如果递归返回 ...
- C语言输入字符串
首先强调一点,C语言没有字符串的概念!所谓的字符串实际上还是以数组形式保存的. 方法1 -- 通过"%s"输入 优点:简单明了,输入字符只要不大于数组长度都可以. #includ ...
- 一台PC端安装多店仓信息的删除
如图所示,安装了多店仓,想要删除其中莫一店仓信息! 步骤一:先找到对应目录,一般默认的目录为C:\Users\xxxx\AppData\Roaming\WebPos2.0\bosnatweiniman ...
- win8.1下jdk的安装和环境变量的配置 eclipse的安装和汉化
1.首先下载jdk安装包,安装的时候会有两个文件安装,一个是jdk一个是jre建议两个文件不要安装在一个目录下 2.安装jdk后面就是配置环境变量,path和classpath,path要在用户变量中 ...
- Rejecting mapping update to [xxx] as the final mapping would have more than 1 type: [xxx, xx]
说明: 1.elasticsearch 版本 6.3.1 2.在同一个index下创建两个type时报错,信息如下: 在创建第二个type:solr时,先前已经在相同索引下创建了一个type:es [ ...
- Hbase原理(转学习自用)
一.系统架构 从HBase的架构图上可以看出,HBase中的组件包括Client.Zookeeper.HMaster.HRegionServer.HRegion.Store.MemStore.Stor ...
- 手动修复 under-replicated blocks in HDFS
解决方式步骤: 1.进入hdfs的pod kubectl get pod -o wide | grep hdfs kubectl exec -ti hadoop-hdfs-namenode-hdfs1 ...
- 快速了解JavaScript的基础知识
注释 单行注释: // 单行注释 多行注释: /* 多行 注释 */ 历史上 JavaScript 可以兼容 HTML 注释,因此 <!-- 和 --> 也可以是单行注释. x = 1; ...
- 【剑指 Offer】05.替换空格
题目描述 请实现一个函数,把字符串 s 中的每个空格替换成"%20". 示例 1: 输入:s = "We are happy." 输出:"We%20a ...
- DHCP最佳实践(二)
这是Windows DHCP最佳实践和技巧的最终指南. 如果您有任何最佳做法或技巧,请在下面的评论中发布它们. 在本指南(二)中,我将分享以下DHCP最佳实践和技巧. 从DHCP作用域中排除IP 了解 ...