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 ...
随机推荐
- postgre sql递归查询
WITH RECURSIVE r AS (SELECT * FROM [表] WHERE id = xxxunion ALLSELECT [表].* FROM [表], r WHERE [表]. ...
- 表单序列化json字符串和js时间格式化
js时间格式化 new Date().format("时间格式") Date.prototype.format = function(fmt) { var o = { ...
- [LeetCode]Subtree of Another Tree判断一棵树是不是另一棵树的子树
将树序列化为字符串,空节点用符号表示,这样可以唯一的表示一棵树. 用list记录所有子树的序列化,和目标树比较. List<String> list = new ArrayList< ...
- 【wp】2020XCTF_逆向
前几天的XCTF最后一场终于打完了,三场比赛下来对逆向部分的大概感觉是从第一场的啥都不会做(一道lua+一道apk)到后来的终于能有参与度,至少后两场的题目都是pc逆向,虽然特殊架构但好歹能做(tcl ...
- jsonp详解及跨域请求
什么是JSONP? JSON是一种轻量级的数据传输格式语言,被广泛应用于当前Web应用中.JSON格式数据的编码和解析基本在所有主流语言中都被实现,所以现在大部分前后端分离的架构都以JSON格式进行数 ...
- 盘点 Java 开发 2020 年发生的几件大事,你必须得知道!
2021 年了,在过去的一年 Java 软件开发行业都发生了哪些重大事件呢? 这篇栈长带大家回顾一下,其实在元旦的<滚蛋吧,2020>也略有介绍,这篇就更加详细的总结一下. 1.Java ...
- Redis基础篇(八)数据分片
现在有一个场景:要用Redis保存5000万个键值对,每个键值对大约是512B,要怎么部署Redis服务呢? 第一个方案,也是最容易想到的,需要保存5000万个键值对,每个键值对约为512B,一共需要 ...
- Sqoop(一)安装及基本使用
Sqoop: 1.sqoop从数据库中导入数据到HDFS 2.SQOOP从数据库导入数据到hive 3.sqoop从hive中将数据导出到数据库 sqoop底层还是执行的m ...
- Win Docker 安装C盘清理方法之一
背景 由于Docker默认安装到C盘,C盘空间越发的小了,虽然(win10)C盘满了并不会很大影响,但是强迫症患者是不能忍得 解决办法 查询https://stackoverflow.com/ques ...
- jQuery中toggle与slideToggle以及fadeToggle的显示、隐藏方法的比较
1.区别 ①动画效果的比较: toggle:直接显示.隐藏,如果有[时间参数]且[匹配的元素有宽度属性],则动态效果为左上角-右下角拉卷效果,透明度0-1之间的变化:若有时间参数但是[匹配的元素没有宽 ...