建议使用以下浏览器,以获得最佳体验。 ie 9.0 以上版本 chrome 31 谷歌浏览器 firefox 30 火狐浏览器
温馨提示

抱歉,您需设置社区昵称后才能参与社区互动!

前往修改
我再想想
选择版块
iot物联网 主题:17572帖子:253389

【技术干货】

驱动开发实战之tcpclient

昨天 22:36 101
--- sidebar_position: 2 title: tcpclient demo --- ## 场景模拟 假设你有一批非标设备需要对接,对方提供了如下协议文档: ### 协议概述 > 设备作为**tcpserver**,端口**6666** > 字节序:**little-endian**,即低地址存放低位 ### 请求回复 > 需要你主动发起读取**请求**:**0x01 02 03 04** > 设备**回复**:**0x08 01 41 d6 3d 71 1a 20** ### 参数说明 1. **总字节数** > (*byte[0]*)即0x08:用于简单的校验 2. **运行状态** > (*byte[1]*)即0x01:1为运行;其他为停止 3. **设备温度** > (*byte[2]-byte[5]*)即0x41 d6 3d 71:单精度浮点数值26.78 4. **电机转速** > (*byte[6]-byte[7]*)即0x1a 20:对应16进制无符号整型,倍率0.01值66.88 ## 驱动开发 我们根据上面的协议,开发驱动。请先浏览上一篇**驱动简介** ### 创建驱动项目 1. 在4008云顶国际网站的解决方案->drivers文件夹,右键添加->新建项目->c#类库 ![create-project.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439684498481290.png) 2. 项目名**driversimtcpclient**,放在```iotgateway\plugins\drivers```路径下 ![project-name.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439697894388869.png) 3. 修改*class1*为*simtcpclient* 4. 双击项目,修改配置 ![edit-project.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439720335671163.png) ```xml title="iotgateway\plugins\drivers\driversimtcpclient\driversimtcpclient.csproj" net6.0 ../../../iotgateway/bin/debug/net6.0/drivers true enable enable ``` :::info 说明 > outputpath节点指定了生成项目的文件夹 > > *simpletcp.core*是一个tcp客户端库(你也可以自己写) > > projectreference节点引用了*plugininterface*项目 > > copylocallockfileassemblies节点可以确保你引用的nuget拷贝到driver文件夹下 ::: ### 编写项目代码 ``` csharp title="iotgateway\plugins\drivers\driversimtcpclient\simtcpclient.cs" using plugininterface; using simpletcp; using system; using system.text; namespace driversimtcpclient { [driversupported("simtcpserverdevice")] [driverinfoattribute("simtcpclient", "v1.0.0", "4008云顶国际网站 copyright iotgateway© 2022-06-04")] public class simtcpclient : idriver { /// /// tcp客户端 /// private simpletcpclient? client; /// /// 缓存最新的服务器返回的原始数据 /// private byte[] latestrcvdata; #region 配置参数 [configparameter("设备id")] public guid deviceid { get; set; } [configparameter("ip地址")] public string ipaddress { get; set; } = "127.0.0.1"; [configparameter("端口号")] public int port { get; set; } = 6666; /// /// 为了演示枚举类型在web端的录入,这里没用到 但是你可以拿到 /// [configparameter("连接类型")] public connectiontype connectiontype { get; set; } = connectiontype.long; [configparameter("超时时间ms")] public int timeout { get; set; } = 300; [configparameter("最小通讯周期ms")] public uint minperiod { get; set; } = 3000; #endregion public simtcpclient(guid deviceid) { deviceid = deviceid; } /// /// 判断连接状态 /// public bool isconnected { get { //客户端对象不为空并且客户端已连接则返回true return client != null && client.tcpclient.connected; } } /// /// 进行连接 /// /// 连接是否成功 public bool connect() { try { //进行连接 client = new simpletcpclient().connect(ipaddress, port); client.datareceived = client_datareceived; } catch (exception) { return false; } return isconnected; } /// /// 收到服务端数据 /// /// /// private void client_datareceived(object? sender, message e) { //如果收到的数据校验正确,则放在内存中 if (e.data.length == 8 && e.data[0] == 0x08) latestrcvdata = e.data; } /// /// 断开连接 /// /// 断开是否成功 public bool close() { try { client.datareceived -= client_datareceived; //断开连接 client?.disconnect(); return !isconnected; } catch (exception) { return false; } } /// /// 释放 /// public void dispose() { try { //释放资源 client?.dispose(); } catch (exception) { } } /// /// 发送数据 /// private byte[] sendcmd = new byte[4] { 0x01, 0x02, 0x03, 0x04 }; /// /// 解析并返回 /// /// ioarg.address为起始变量字节编号;ioarg.valuetype为类型 /// [method("读模拟设备数据", description: "读模拟设备数据,开始字节和长度")] public driverreturnvaluemodel read(driveraddressioargmodel ioarg) { var ret = new driverreturnvaluemodel { statustype = varibalestatustypeenum.good }; ushort startindex; //判断地址是否为整数 if (!ushort.tryparse(ioarg.address, out startindex)) { ret.statustype = varibalestatustypeenum.bad; ret.message = "起始字节编号错误"; return ret; } //连接正常则进行读取 if (isconnected) { try { //发送请求 client?.write(sendcmd); //等待恢复,这里可以优化 thread.sleep(timeout); if (latestrcvdata == null) { ret.statustype = varibalestatustypeenum.bad; ret.message = "没有收到数据"; } else { //解析数据,并返回 switch (ioarg.valuetype) { case datatypeenum.ubyte: case datatypeenum.byte: ret.value = latestrcvdata[startindex]; break; case datatypeenum.int16: var buffer16 = latestrcvdata.skip(startindex).take(2).toarray(); ret.value = bitconverter.toint16(new byte[] { buffer16[0], buffer16[1] }, 0); break; case datatypeenum.float: //拿到有用的数据 var buffer32 = latestrcvdata.skip(startindex).take(4).toarray(); //大小端转换一下 ret.value = bitconverter.tosingle(new byte[] { buffer32[3], buffer32[2], buffer32[1], buffer32[0] }, 0); break; default: break; } } } catch (exception ex) { ret.statustype = varibalestatustypeenum.bad; ret.message = $"读取失败,{ex.message}"; } } else { ret.statustype = varibalestatustypeenum.bad; ret.message = "连接失败"; } return ret; } public async task writeasync(string requestid, string method, driveraddressioargmodel ioarg) { rpcresponse rpcresponse = new() { issuccess = false, description = "设备驱动内未实现写入功能" }; return rpcresponse; } } public enum connectiontype { long, short } } ``` ### 注册驱动 1. 生成```driversimtcpclient ```项目 > ```iotgateway\iotgateway\bin\debug\net6.0\drivers\net6.0```路径下可以看到生成了*driversimtcpclient.dll* 2. 运行iotgateway,访问本地518端口 3. 添加驱动 > 网关配置->驱动管理->添加 ![add-driver.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439737534439536.png) :::warning 注意 > 添加驱动后需要重启一下项目,后面会优化 ::: ### 创建设备 1. 采集配置->设备维护->添加设备 ![add-device.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439744939873543.png) ### 添加变量 1. 采集配置->设备维护->添加设备 > 手动添加或者通过excel批量导入下面变量 | 变量名 | 方法 | 地址 | 类型 | 表达式 | 设备名 | | ------- | ----- | ----- | ----| ------ | ------ | | 运行状态 | read | 1 |uint8 | |模拟设备 | | 设备温度 | read | 2 |float | |模拟设备 | | 电机转速 | read | 6 |int16 |raw*0.01 |模拟设备 | ## 开始采集 采集配置->设备维护->编辑设备 ![start-datacollect.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439752396380616.png) ## 启动tcpserver 运行你熟悉的tcpserver测试工具,启动端口6666,网关客户端连接后发送响应报文 ![start-tcpserver.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439756997421992.png) ## 查看数据

回复9

1 0
2022/6/5 22:38

基于.net6的跨平台物联网网关。通过可视化配置,轻松的连接到你的任何设备和系统(如plc、扫码枪、cnc、数据库、串口设备、上位机、opc server、opc ua server、mqtt server等),从而与 thingsboard、iotsharp或您自己的物联网平台进行双向数据通讯。提供简单的驱动开发接口;当然也可以进行边缘计算。 项目地址:https://gitee.com/iioter/iotgateway 项目地址:https://github.com/iioter/iotgateway 项目文档:http://iotgateway.net 在线体验:http://iotgateway.net:518

12 小时前

不错,已star
... 展开
0 0
2022/6/5 22:51

感谢精彩分享 
                                          -- 高级云网管

0 0
2022/6/6 08:26

感谢分享

0 0
2022/6/6 10:02

感谢分享

0 0
2022/6/6 10:58

感谢分享

0 0
2022/6/6 12:19

感谢分享~~

0 0
2022/6/6 13:48

666,看起来真不错呀

0 0
2022/6/6 21:46

感谢精彩分享 
                                          -- 高级云网管

0 0
2022/6/6 21:56

谢谢分享

上划加载中
直达楼层
全部回复
正序浏览
标签
您还可以添加5个标签
  • 没有搜索到和“关键字”相关的标签
  • 云产品
  • 4008云顶国际网站的解决方案
  • 技术领域
  • 通用技术
  • 平台功能
取消

驱动开发实战之tcpclient-4008云顶国际网站

您已采纳当前回复为最佳回复

发帖: 4粉丝: 0

发表于2022年06月05日 22:36:05 101 9
[技术干货] 驱动开发实战之tcpclient
--- sidebar_position: 2 title: tcpclient demo --- ## 场景模拟 假设你有一批非标设备需要对接,对方提供了如下协议文档: ### 协议概述 > 设备作为**tcpserver**,端口**6666** > 字节序:**little-endian**,即低地址存放低位 ### 请求回复 > 需要你主动发起读取**请求**:**0x01 02 03 04** > 设备**回复**:**0x08 01 41 d6 3d 71 1a 20** ### 参数说明 1. **总字节数** > (*byte[0]*)即0x08:用于简单的校验 2. **运行状态** > (*byte[1]*)即0x01:1为运行;其他为停止 3. **设备温度** > (*byte[2]-byte[5]*)即0x41 d6 3d 71:单精度浮点数值26.78 4. **电机转速** > (*byte[6]-byte[7]*)即0x1a 20:对应16进制无符号整型,倍率0.01值66.88 ## 驱动开发 我们根据上面的协议,开发驱动。请先浏览上一篇**驱动简介** ### 创建驱动项目 1. 在4008云顶国际网站的解决方案->drivers文件夹,右键添加->新建项目->c#类库 ![create-project.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439684498481290.png) 2. 项目名**driversimtcpclient**,放在```iotgateway\plugins\drivers```路径下 ![project-name.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439697894388869.png) 3. 修改*class1*为*simtcpclient* 4. 双击项目,修改配置 ![edit-project.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439720335671163.png) ```xml title="iotgateway\plugins\drivers\driversimtcpclient\driversimtcpclient.csproj" net6.0 ../../../iotgateway/bin/debug/net6.0/drivers true enable enable ``` :::info 说明 > outputpath节点指定了生成项目的文件夹 > > *simpletcp.core*是一个tcp客户端库(你也可以自己写) > > projectreference节点引用了*plugininterface*项目 > > copylocallockfileassemblies节点可以确保你引用的nuget拷贝到driver文件夹下 ::: ### 编写项目代码 ``` csharp title="iotgateway\plugins\drivers\driversimtcpclient\simtcpclient.cs" using plugininterface; using simpletcp; using system; using system.text; namespace driversimtcpclient { [driversupported("simtcpserverdevice")] [driverinfoattribute("simtcpclient", "v1.0.0", "4008云顶国际网站 copyright iotgateway© 2022-06-04")] public class simtcpclient : idriver { /// /// tcp客户端 /// private simpletcpclient? client; /// /// 缓存最新的服务器返回的原始数据 /// private byte[] latestrcvdata; #region 配置参数 [configparameter("设备id")] public guid deviceid { get; set; } [configparameter("ip地址")] public string ipaddress { get; set; } = "127.0.0.1"; [configparameter("端口号")] public int port { get; set; } = 6666; /// /// 为了演示枚举类型在web端的录入,这里没用到 但是你可以拿到 /// [configparameter("连接类型")] public connectiontype connectiontype { get; set; } = connectiontype.long; [configparameter("超时时间ms")] public int timeout { get; set; } = 300; [configparameter("最小通讯周期ms")] public uint minperiod { get; set; } = 3000; #endregion public simtcpclient(guid deviceid) { deviceid = deviceid; } /// /// 判断连接状态 /// public bool isconnected { get { //客户端对象不为空并且客户端已连接则返回true return client != null && client.tcpclient.connected; } } /// /// 进行连接 /// /// 连接是否成功 public bool connect() { try { //进行连接 client = new simpletcpclient().connect(ipaddress, port); client.datareceived = client_datareceived; } catch (exception) { return false; } return isconnected; } /// /// 收到服务端数据 /// /// /// private void client_datareceived(object? sender, message e) { //如果收到的数据校验正确,则放在内存中 if (e.data.length == 8 && e.data[0] == 0x08) latestrcvdata = e.data; } /// /// 断开连接 /// /// 断开是否成功 public bool close() { try { client.datareceived -= client_datareceived; //断开连接 client?.disconnect(); return !isconnected; } catch (exception) { return false; } } /// /// 释放 /// public void dispose() { try { //释放资源 client?.dispose(); } catch (exception) { } } /// /// 发送数据 /// private byte[] sendcmd = new byte[4] { 0x01, 0x02, 0x03, 0x04 }; /// /// 解析并返回 /// /// ioarg.address为起始变量字节编号;ioarg.valuetype为类型 /// [method("读模拟设备数据", description: "读模拟设备数据,开始字节和长度")] public driverreturnvaluemodel read(driveraddressioargmodel ioarg) { var ret = new driverreturnvaluemodel { statustype = varibalestatustypeenum.good }; ushort startindex; //判断地址是否为整数 if (!ushort.tryparse(ioarg.address, out startindex)) { ret.statustype = varibalestatustypeenum.bad; ret.message = "起始字节编号错误"; return ret; } //连接正常则进行读取 if (isconnected) { try { //发送请求 client?.write(sendcmd); //等待恢复,这里可以优化 thread.sleep(timeout); if (latestrcvdata == null) { ret.statustype = varibalestatustypeenum.bad; ret.message = "没有收到数据"; } else { //解析数据,并返回 switch (ioarg.valuetype) { case datatypeenum.ubyte: case datatypeenum.byte: ret.value = latestrcvdata[startindex]; break; case datatypeenum.int16: var buffer16 = latestrcvdata.skip(startindex).take(2).toarray(); ret.value = bitconverter.toint16(new byte[] { buffer16[0], buffer16[1] }, 0); break; case datatypeenum.float: //拿到有用的数据 var buffer32 = latestrcvdata.skip(startindex).take(4).toarray(); //大小端转换一下 ret.value = bitconverter.tosingle(new byte[] { buffer32[3], buffer32[2], buffer32[1], buffer32[0] }, 0); break; default: break; } } } catch (exception ex) { ret.statustype = varibalestatustypeenum.bad; ret.message = $"读取失败,{ex.message}"; } } else { ret.statustype = varibalestatustypeenum.bad; ret.message = "连接失败"; } return ret; } public async task writeasync(string requestid, string method, driveraddressioargmodel ioarg) { rpcresponse rpcresponse = new() { issuccess = false, description = "设备驱动内未实现写入功能" }; return rpcresponse; } } public enum connectiontype { long, short } } ``` ### 注册驱动 1. 生成```driversimtcpclient ```项目 > ```iotgateway\iotgateway\bin\debug\net6.0\drivers\net6.0```路径下可以看到生成了*driversimtcpclient.dll* 2. 运行iotgateway,访问本地518端口 3. 添加驱动 > 网关配置->驱动管理->添加 ![add-driver.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439737534439536.png) :::warning 注意 > 添加驱动后需要重启一下项目,后面会优化 ::: ### 创建设备 1. 采集配置->设备维护->添加设备 ![add-device.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439744939873543.png) ### 添加变量 1. 采集配置->设备维护->添加设备 > 手动添加或者通过excel批量导入下面变量 | 变量名 | 方法 | 地址 | 类型 | 表达式 | 设备名 | | ------- | ----- | ----- | ----| ------ | ------ | | 运行状态 | read | 1 |uint8 | |模拟设备 | | 设备温度 | read | 2 |float | |模拟设备 | | 电机转速 | read | 6 |int16 |raw*0.01 |模拟设备 | ## 开始采集 采集配置->设备维护->编辑设备 ![start-datacollect.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439752396380616.png) ## 启动tcpserver 运行你熟悉的tcpserver测试工具,启动端口6666,网关客户端连接后发送响应报文 ![start-tcpserver.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/5/1654439756997421992.png) ## 查看数据

分享文章到朋友圈

分享文章到微博
您已采纳当前回复为最佳回复

发帖: 4粉丝: 0

发表于2022年06月05日 22:38:51

基于.net6的跨平台物联网网关。通过可视化配置,轻松的连接到你的任何设备和系统(如plc、扫码枪、cnc、数据库、串口设备、上位机、opc server、opc ua server、mqtt server等),从而与 thingsboard、iotsharp或您自己的物联网平台进行双向数据通讯。提供简单的驱动开发接口;当然也可以进行边缘计算。 项目地址:https://gitee.com/iioter/iotgateway 项目地址:https://github.com/iioter/iotgateway 项目文档:http://iotgateway.net 在线体验:http://iotgateway.net:518

评论
kswil 12 小时前

不错,已star

... 查看全部
您已采纳当前回复为最佳回复

发帖: 58粉丝: 10

发表于2022年06月05日 22:51:21

感谢精彩分享 
                                          -- 高级云网管

您已采纳当前回复为最佳回复

发帖: 100粉丝: 7

发表于2022年06月06日 08:26:57

感谢分享

您已采纳当前回复为最佳回复

kswil

发帖: 336粉丝: 2

发表于2022年06月06日 10:02:51

感谢分享

您已采纳当前回复为最佳回复

发帖: 91粉丝: 0

发表于2022年06月06日 10:58:07

感谢分享

您已采纳当前回复为最佳回复

小糖饼最甜呀

发帖: 95粉丝: 1

发表于2022年06月06日 12:19:59

感谢分享~~

您已采纳当前回复为最佳回复

发帖: 54粉丝: 31

发表于2022年06月06日 13:48:11

666,看起来真不错呀

您已采纳当前回复为最佳回复

发帖: 58粉丝: 10

发表于2022年06月06日 21:46:46

感谢精彩分享 
                                          -- 高级云网管

您已采纳当前回复为最佳回复

发帖: 33粉丝: 1

发表于2022年06月06日 21:56:31

谢谢分享

您需要登录后才可以回帖 | 立即注册

您对问题的回复是否满意?
满意度
非常满意 满意 一般 不满意
我要反馈
0/200
网站地图