OPCUA结构体的读写说白了就是对ExtensionObject中按规则对byte的转换

读取步骤:

1.首先可以先用UAExpert查看结构体

2.读取出结构体DataValue的值

3.把读取出来的值转换成ExtensionObject[]

4.把ExtensionObject中每项进行解析。

具体步骤解析:

1.首先可以先用UAExpert查看

如图1我们能看到有一个结构体的数据类型ExtensionObject。这个结构体的有5项,且每个字段都是什么。(这里主要验证我们后期自己读取的数据对不对)

图1

2.读取出结构体DataValue的值

这里我们通过session中的ReadValue()方法读取出结构体DataValue的值,这里和正常的已知nodeID读值方法一样(怎么建立连接,大家可以搜随便搜一下就能找到,或者也可以看我前面OPCUA的文章)。

           DataValue item= m_session.ReadValue(new NodeId(ItemAdress));

3.把读取出来的值转换成ExtensionObject[]

读取后我们可以看到value的值,如图2,它是一个ExtensionObject类型长为100的数据。而且每项都是byte[],我们要做的就是如何把byte按照规则转换成字符

4.把ExtensionObject中每项进行解析。

首先我们先得到ExtensionObject中的结构体的项,下面代码中typeDefine中就能看到结构体中的所有项,大家可以打个断点看看

            NodeId node = new NodeId(ItemAdress);//获取Node 信息 验证Node的数据类型VariableNode nodeInfo = m_session.ReadNode(node) as VariableNode;//DataValue value = m_session.ReadValue(node);var datatypeNode = (m_session.ReadNode(nodeInfo.DataType)) as DataTypeNode;var typeDefine = datatypeNode.DataTypeDefinition.Body as StructureDefinition;

然后就是遍历所有项,其中GetJsonFromExtensionObject就是对每项就行解析

            if (value.Value is ExtensionObject[])//数组{JArray res = new JArray();foreach (var item in value.Value as ExtensionObject[]){res.Add(GetJsonFromExtensionObject(item, typeDefine,ref index));}return res.ToString();}

最后对每项项进行解析时,要和相关人员确定byte[]拼接的规则。比如我这里如果该项是字符串,那么首先需要先读取该字符串所占的长度,然后根据长度读取字符串。当然具体项目中的规则也可能不完全相同,但是思路是一样的。如果是int,float直接读取4个byte,bool读取1个byte,double读取8个byte,根据一个类型占多少位决定。下面代码可供参考

        private JObject GetJsonFromExtensionObject(ExtensionObject value, StructureDefinition structure,ref int index){JObject res = new JObject();var data = value.Body as byte[];foreach (var field in structure.Fields){if (field.DataType.NamespaceIndex==2){var count = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);index += 4;var datatypeNode1 = (m_session.ReadNode(field.DataType)) as DataTypeNode;var typeDefine = datatypeNode1.DataTypeDefinition.Body as StructureDefinition;for (int i = 0; i < count; i++){res[field.Name+i] =GetJsonFromExtensionObject(value, typeDefine,ref index);}}string name = field.Name;if (field.DataType == DataTypeIds.String){int length = (int)BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);//读取字符串所占长度index += 4;string re = Encoding.Default.GetString(data.Skip(index).Take(length).ToArray());//根据字符串长度读取字符串res[name] = re;index += length;}if (field.DataType == DataTypeIds.UInt32){UInt32 re = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);index += 4;res[name] = re;}if (field.DataType == DataTypeIds.Float){float re = BitConverter.ToSingle(data.Skip(index).Take(4).ToArray(), 0);index += 4;res[name] = re;}if (field.DataType == DataTypeIds.Boolean){bool re = BitConverter.ToBoolean(data.Skip(index).Take(1).ToArray());res[name] = re;index += 1;}if (field.DataType == DataTypeIds.Double){double re = BitConverter.ToDouble(data.Skip(index).Take(8).ToArray());res[name] = re;index += 8;}}return res;}

读取结构体完整代码如下:

public string structItem(string ItemAdress){DataValue item= m_session.ReadValue(new NodeId(ItemAdress));string aaa = ReadStruct(ItemAdress, item);return aaa;}/// <summary>/// 读取结构体数据/// </summary>public string ReadStruct(string ItemAdress, DataValue value){#region 得到ExtensionObject中的结构体的项NodeId node = new NodeId(ItemAdress);//获取Node 信息 验证Node的数据类型VariableNode nodeInfo = m_session.ReadNode(node) as VariableNode;//DataValue value = m_session.ReadValue(node);var datatypeNode = (m_session.ReadNode(nodeInfo.DataType)) as DataTypeNode;var typeDefine = datatypeNode.DataTypeDefinition.Body as StructureDefinition;#endregionint index = 0;if (value.Value is ExtensionObject[])//数组{JArray res = new JArray();foreach (var item in value.Value as ExtensionObject[]){res.Add(GetJsonFromExtensionObject(item, typeDefine,ref index));}return res.ToString();}else //非数组{return GetJsonFromExtensionObject(value.Value as ExtensionObject, typeDefine, ref index).ToString();}}private JObject GetJsonFromExtensionObject(ExtensionObject value, StructureDefinition structure,ref int index){JObject res = new JObject();var data = value.Body as byte[];foreach (var field in structure.Fields){if (field.DataType.NamespaceIndex==2){var count = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);index += 4;var datatypeNode1 = (m_session.ReadNode(field.DataType)) as DataTypeNode;var typeDefine = datatypeNode1.DataTypeDefinition.Body as StructureDefinition;for (int i = 0; i < count; i++){res[field.Name+i] =GetJsonFromExtensionObject(value, typeDefine,ref index);}}string name = field.Name;if (field.DataType == DataTypeIds.String){int length = (int)BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);//读取字符串所占长度index += 4;string re = Encoding.Default.GetString(data.Skip(index).Take(length).ToArray());//根据字符串长度读取字符串res[name] = re;index += length;}if (field.DataType == DataTypeIds.UInt32){UInt32 re = BitConverter.ToUInt32(data.Skip(index).Take(4).ToArray(), 0);index += 4;res[name] = re;}if (field.DataType == DataTypeIds.Float){float re = BitConverter.ToSingle(data.Skip(index).Take(4).ToArray(), 0);index += 4;res[name] = re;}if (field.DataType == DataTypeIds.Boolean){bool re = BitConverter.ToBoolean(data.Skip(index).Take(1).ToArray());res[name] = re;index += 1;}if (field.DataType == DataTypeIds.Double){double re = BitConverter.ToDouble(data.Skip(index).Take(8).ToArray());res[name] = re;index += 8;}}return res;}

写入步骤:

1.首先可以先用UAExpert查看结构体

2.把每项的结构体转成把ExtensionObject,加入到ExtensionObject[]

3.把ExtensionObject[]写入即可

写入结构体的难点就是如何按照规则(就是拼接方式)把结构体转成byte[]然后加入到ExtensionObject[]

1.首先可以先用UAExpert查看结构体

同读取,省略

2.把每项的结构体转成把ExtensionObject,加入到ExtensionObject[]

首先定义一个结构体类,同UAExpert查看结构体,注意结构体顺序也不能乱

    /// <summary>/// writevar对象/// </summary>public class WriteVar{/// <summary>/// 数组索引/// </summary>public int index = 0;/// <summary>/// 数据项名称/// </summary>public string Name = "";/// <summary>/// 数据类型/// </summary>public int DataType = 0;/// <summary>/// 字符串值/// </summary>public string StringValue = "";/// <summary>/// 整数值/// </summary>public int IntValue = 0;/// <summary>/// 浮点数值/// </summary>public float FloatValue = 0.0F;}

然后赋值给结构体,并转成ExtensionObject,这里我定义的规则就是如果是字符串就要把长度也拼接上

            WriteVar structs = new WriteVar{index = 4,Name = "重量",DataType = 0,StringValue = "",IntValue = 25,FloatValue = 0.0F};var result = Pro_OPCUA.GetValueByteFromObj(structs);/// <summary>/// 从对象中获取对象所有的值,并转化为byte[]/// </summary>/// <param name="value">需要写入节点的值组成的byte数组列表</param>/// <returns></returns>public static ExtensionObject GetValueByteFromObj(WriteVar value){List<byte> result = new List<byte>();//前4位为字符串数据长度var length = BitConverter.GetBytes(value.Name.Length);result.AddRange(length);//数据项名称var Name = Encoding.Default.GetBytes(value.Name);result.AddRange(Name);//数据类型var DataType = BitConverter.GetBytes(value.DataType);result.AddRange(DataType);//字符串数据转换if (value.StringValue.Length==0){result.AddRange(new byte[4] { 0,0,0,0});}else{//前4位为字符串数据长度length = BitConverter.GetBytes(value.StringValue.Length);result.AddRange(length);//字符串数据var StringValue = Encoding.Default.GetBytes(value.StringValue);result.AddRange(StringValue);}//整数数据var IntValue = BitConverter.GetBytes(value.IntValue);result.AddRange(IntValue);//浮点数数据var FloatValue = BitConverter.GetBytes(value.FloatValue);result.AddRange(FloatValue);return new ExtensionObject {Body= result.ToArray() } ;}

3.把ExtensionObject[]写入即可

其实拼接好ExtensionObject[]后按照通用写OPCUA的方法就可以了

        }/// <summary>/// OPCUATag写入/// </summary>/// <param name="value">需要写入节点的值组成的byte数组列表</param>/// <returns></returns>public void WriteVarStruct(ExtensionObject[] value,string nodeId){WriteValueCollection nodesToWrite = new WriteValueCollection();nodesToWrite.Add(new WriteValue(){NodeId = new NodeId(nodeId),AttributeId = Attributes.Value,Value = new DataValue(){Value = value}});WriteNode(nodesToWrite);}/// <summary>/// OPCUATag写入/// </summary>/// <param name="adress">需要写入节点的地址</param>/// <param name="value">需要写入节点的值</param>/// <returns></returns>public bool WriteNode(WriteValueCollection value){try{//if (isCconnect)//{StatusCodeCollection resultsValues = null;DiagnosticInfoCollection diagnosticInfos = null;//Console.WriteLine("数据读取开始");// Call Read Servicevar result = m_session.Write(null,value,out resultsValues,out diagnosticInfos);//写入返回值为bad,则写入失败if (StatusCode.IsBad(result.ServiceResult)){return false;}//验证结果ClientBase.ValidateResponse(resultsValues, value);return true;//}//return false;}catch (Exception ex){throw new Exception("OPUAReadNodes:" + ex.Message + ex.StackTrace);}}

写结构体的完整代码:

        private void button6_Click(object sender, EventArgs e){ExtensionObject[] AA = new ExtensionObject[100];for (int i = 0; i < AA.Length; i++){AA[i] = new ExtensionObject { Body = getNewByte() };}WriteVar structs = new WriteVar{index = 4,Name = "重量",DataType = 0,StringValue = "",IntValue = 25,FloatValue = 0.0F};var result = Pro_OPCUA.GetValueByteFromObj(structs);AA[4] = result;float a = 1.23F;WriteVar structs1 = new WriteVar{index = 5,Name = "形状",DataType = 1,StringValue = "",IntValue = 0,FloatValue = a};var result1 = Pro_OPCUA.GetValueByteFromObj(structs1);AA[5] = result1;WriteVar structs2 = new WriteVar{index = 6,Name = "C",DataType = 2,StringValue = "WUXE",IntValue = 0,FloatValue = 0.0F};var result2= Pro_OPCUA.GetValueByteFromObj(structs2);AA[6] = result2;//byte[] re = new byte[23] { 3,0,0,0,56,56,56,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0};string aaa= AA.ToString();pro_OPCUAp.WriteVarStruct(AA, "ns=2;s=writeStrucat");}/// <summary>/// OPCUATag写入/// </summary>/// <param name="value">需要写入节点的值组成的byte数组列表</param>/// <returns></returns>public void WriteVarStruct(ExtensionObject[] value,string nodeId){WriteValueCollection nodesToWrite = new WriteValueCollection();nodesToWrite.Add(new WriteValue(){NodeId = new NodeId(nodeId),AttributeId = Attributes.Value,Value = new DataValue(){Value = value}});WriteNode(nodesToWrite);}/// <summary>/// OPCUATag写入/// </summary>/// <param name="adress">需要写入节点的地址</param>/// <param name="value">需要写入节点的值</param>/// <returns></returns>public bool WriteNode(WriteValueCollection value){try{//if (isCconnect)//{StatusCodeCollection resultsValues = null;DiagnosticInfoCollection diagnosticInfos = null;//Console.WriteLine("数据读取开始");// Call Read Servicevar result = m_session.Write(null,value,out resultsValues,out diagnosticInfos);//写入返回值为bad,则写入失败if (StatusCode.IsBad(result.ServiceResult)){return false;}//验证结果ClientBase.ValidateResponse(resultsValues, value);return true;//}//return false;}catch (Exception ex){throw new Exception("OPUAReadNodes:" + ex.Message + ex.StackTrace);}}

项目地址:

OPCUA读写结构体示例-C#文档类资源-CSDN文库

C# OPCUA 读写结构体相关推荐

  1. QT 使用数据流方式QDataSteam读写结构体数据

    文章目录 一.QT中保存单个变量到文件中 二.使用memcpy读写结构体数据 一.QT中保存单个变量到文件中 在QT中使用QDateStream进行数据流文件读写,保存数据(QT帮助中的例子). Ex ...

  2. C语言文件读写(结构体文件)

    有时候,我们需要将输入的数据存储起来,这时候就需要用到文件,对于C语言而言,文件的读写有多种方式,下面主要是结构体文件的读写,例如student.dat(第一列是学号,第二列是姓名) 20180001 ...

  3. Win32:INI文件读写结构体/Int/String/遍历

    目录 一.INI的结构和用途 1.1 格式 1.2 INI文件示例 1.3 实例 二.怎么写入一个节Section 三.怎么读/写键值对 3.1.读/写String 3.2.读/写Int 3.3.读/ ...

  4. c语言 将结构体放在flash,stm32的内部flash读写操作(含结构体的保存)

    不同的stm32单片机的flash大小不同,这个需要查阅芯片手册或者查看STM32CubeMX软件. stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实 ...

  5. 33. 使用fread()/fwrite()往文件中写入结构体,从文件中读出结构体

    1 //读写结构体 2 #include <stdio.h> 3 typedef struct student 4 { 5 int num; 6 char name[30]; 7 char ...

  6. c语言怎么往结构体中传数据,怎么把文件数据写入结构体 c语言 怎么将结构体写入文件...

    怎么把结构体的数据写到文件中 C语言把一个结构体数组写入文件分三步: 以二进制写方式(wb)打开文件 调用写入函数fwrite()将结构体数据写入文件 关闭文件指针 相应的,读文件也要与之匹配: 以二 ...

  7. c语言中将结构体写入文件,C语言中将结构体写入文件

    可以使用fwrite()将一个结构体写入文件: fwrite(&some_struct,sizeof somestruct,1,fp); 对应的fread函数可以再把它读出来,此处fwrite ...

  8. c语言fwrite函数结构体,fwrite函数的一般调用形式是什么?

    fwrite函数的一般调用形式是"fwrite(buffer,size,count,fp);":其中,buffer是准备输出的数据块的起始地址,size是每个数据块的字节数,cou ...

  9. 基于结构体的二进制文件读写

    基于结构体的二进制文件读写 项目介绍 工程创建 结构体的创建 写二进制文件 结果 读二进制文件 结果 参考文献 项目介绍 本次设计是为了提高读写二进制文件的效率,以约定的结构体形式进行读写操作,避免了 ...

最新文章

  1. C语言 —— 整型(int)类型数据,做函数的参数,传值与传地址
  2. Spring.net与Asp.net Mvc结合示例《转载》
  3. List类系列(一):list中各元素出现的次数
  4. html鼠标点击有手势出来,用原生js+css3撸的一个下拉手势事件插件
  5. linux rpm 删除
  6. 使用delegate类型设计自定义事件
  7. Egg框架入门教程合集之插件/工具/教程/专栏/开源项目
  8. 【转】Linux下gcc编译生成动态链接库*.so文件并调用它
  9. 900万注释图像数据集升级了!谷歌开放Open Images V6,首增语音、文本、鼠标轨迹同步注释...
  10. fr4走线宽度_PCB布线走线宽度变化的影响分析
  11. linux和emwin的区别,emWin“自带软件GUIBuilder的使用”
  12. PHP编程中如何做到有效配置Apache
  13. 解决 Cannot locate a 64-bit Oracle Client library 问题
  14. matlab停止运行命令_从命令行运行m文件时,如何隐藏“ MATLAB命令窗口”?
  15. Google系列Android手机无法联网/无法上网/WIFI网络受限等问题的解决方法
  16. win配置pm2开机自启node项目
  17. 【秋钓皮皮】 奔跑吧,皮皮!(有图了)
  18. Android截屏的几种实现
  19. Windows 10家庭中文版中启用WSL 2
  20. 浅谈中国IT教育培训机构

热门文章

  1. linux后加网卡,Linux添加网卡教程
  2. Softmax-with-Loss层的计算图 | Softmax梯度推导 | Loss损失函数
  3. win10 更新计算机时间,win10更新时间太长怎么回事_windows10更新时间太久解决教程...
  4. PLETL的主谓宾 定状补模式 命令 已经设计更新并执行成功如图 中节点 的m_ID 输出已经出现 ,已经开源
  5. 华三模拟器命令(陆续更新)
  6. python之AQI分析与预测
  7. html图片轮播放大,jquery+CSS3实现轮播图、js实现轮播图片自适应等比显示、图片旋转、图片拖拽、鼠标滚动放大缩小...
  8. 微信小游戏开发新手教程14-整合到一起,做出你的小游戏
  9. java达内小发猫课程,详细说明
  10. 病毒防治:清除***从它的寄生地开始