翼度科技»论坛 编程开发 .net 查看内容

基于surging 的木舟平台如何通过Tcp或者UDP网络组件接入设备

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
一、概述

      上篇文章介绍了木舟通过HTTP网络组件接入设备,那么此篇文章将介绍如何利用Tcp或者UDP网络组件接入设备.
      木舟 (Kayak) 是什么?
       木舟(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还有多协议适配(TCP,MQTT,UDP,CoAP,HTTP,Grpc,websocket,rtmp,httpflv,webservice,等),通过灵活多样的配置适配能够接入不同厂家不同协议等设备。并且通过设备告警,消息通知,数据可视化等功能。能够让你能快速建立起微服务物联网平台系统。
     那么下面就为大家介绍如何从创建组件、协议、设备网关,设备到设备网关接入,再到设备数据上报,把整个流程通过此篇文章进行阐述。
二、网络组件

1.编辑创建Tcp协议的网络组件,可以选择共享配置和独立配置(独立配置是集群模式). 下图是解析方式选择了自定义脚本进行解码操作。

 还可以选择其它解析方式:如下图

 
 2. 编辑创建UDP协议的网络组件,可以选择共享配置和独立配置(独立配置是集群模式). 可以选择单播或组播。

 
三、自定义协议


  • 如何创建自定义协议模块
如果是网络编程开发,必然会涉及到协议报文的编码解码处理,那么对于平台也是做到了灵活处理,首先是协议模块创建,通过以下代码看出协议模块可以添加协议说明md文档, 身份鉴权处理,消息编解码,元数据配置。下面一一介绍如何进行编写
  1. public class Demo3ProtocolSupportProvider : ProtocolSupportProvider
  2. {
  3.      public override IObservable<ProtocolSupport> Create(ProtocolContext context)
  4.      {
  5.          var support = new ComplexProtocolSupport();
  6.          support.Id = "demo_3";
  7.          support.Name = "演示协议3";
  8.          support.Description = "演示协议3";
  9.          support.AddAuthenticator(MessageTransport.Tcp, new Demo5Authenticator());
  10.          support.AddDocument(MessageTransport.Tcp, "Document/document-tcp.md");
  11.          support.Script = "\r\nvar decode=function(buffer)\r\n{\r\n  parser.Fixed(5).Handler(\r\n function(buffer){ \r\n      var bytes = BytesUtils.GetBytes(buffer,1,4);\r\n      var len = BytesUtils.LeStrToInt(bytes,1,4);//2. 获取消息长度.\r\n       var buf = BytesUtils.Slice(buffer,0,5); \r\n parser.Fixed(len).Result(buf); \r\n        }).Handler(function(buffer){ parser.Result(buffer).Complete();  \r\n        }\r\n )\r\n}\r\nvar encode=function(buffer)\r\n{\r\n}";      
  12.          support.AddMessageCodecSupport(MessageTransport.Tcp, () => Observable.Return(new ScriptDeviceMessageCodec(support.Script)));
  13.          support.AddConfigMetadata(MessageTransport.Tcp, _tcpConfig);
  14.          support.AddAuthenticator(MessageTransport.Udp, new Demo5Authenticator());
  15.          support.Script = "\r\nvar decode=function(buffer)\r\n{\r\n  parser.Fixed(5).Handler(\r\n function(buffer){ \r\n      var bytes = BytesUtils.GetBytes(buffer,1,4);\r\n      var len = BytesUtils.LeStrToInt(bytes,1,4);//2. 获取消息长度.\r\n       var buf = BytesUtils.Slice(buffer,0,5); \r\n parser.Fixed(len).Result(buf); \r\n        }).Handler(function(buffer){ parser.Result(buffer).Complete();  \r\n        }\r\n )\r\n}\r\nvar encode=function(buffer)\r\n{\r\n}";
  16.          support.AddMessageCodecSupport(MessageTransport.Udp, () => Observable.Return(new ScriptDeviceMessageCodec(support.Script)));
  17.          support.AddConfigMetadata(MessageTransport.Udp, _udpConfig);
  18.          return Observable.Return(support);
  19.      }
  20. }
复制代码
1. 添加协议说明文档如代码: support.AddDocument(MessageTransport.Tcp, "Document/document-tcp.md");,文档仅支持 markdown文件,如下所示
 
  1. ### 认证说明
  2. CONNECT报文:
  3. ```text
  4. clientId: 设备ID
  5. password: md5(timestamp+"|"+secureKey)
  6. ```
复制代码
 
2. 添加身份鉴权如代码:  support.AddAuthenticator(MessageTransport.Http, new Demo5Authenticator()) ,自定义身份鉴权Demo5Authenticator 代码如下:
 
  1. public class Demo5Authenticator : IAuthenticator
  2.        {
  3.            public IObservable<AuthenticationResult> Authenticate(IAuthenticationRequest request, IDeviceOperator deviceOperator)
  4.            {
  5.                var result = Observable.Return<AuthenticationResult>(default);
  6.                if (request is DefaultAuthRequest)
  7.                {
  8.                    var authRequest = request as DefaultAuthRequest;
  9.                    deviceOperator.GetConfig(authRequest.GetTransport()==MessageTransport.Http?"token": "key").Subscribe(  config =>
  10.                    {
  11.                        var password = config.Convert<string>();
  12.                        if (authRequest.Password.Equals(password))
  13.                        {
  14.                            result= result.Publish(AuthenticationResult.Success(authRequest.DeviceId));
  15.                        }
  16.                        else
  17.                        {
  18.                            result= result.Publish(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "验证失败,密码错误"));
  19.                        }
  20.                    });
  21.                }
  22.                else
  23.                result = Observable.Return<AuthenticationResult>(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "不支持请求参数类型"));
  24.                return result;
  25.            }
  26.            public IObservable<AuthenticationResult> Authenticate(IAuthenticationRequest request, IDeviceRegistry registry)
  27.            {
  28.                var result = Observable.Return<AuthenticationResult>(default);
  29.                var authRequest = request as DefaultAuthRequest;
  30.                registry
  31.                  .GetDevice(authRequest.DeviceId)
  32.                  .Subscribe(async p => {
  33.                     var config=  await p.GetConfig(authRequest.GetTransport() == MessageTransport.Http ? "token" : "key");
  34.                      var password= config.Convert<string>();
  35.                     if(authRequest.Password.Equals(password))
  36.                      {
  37.                          result= result.Publish(AuthenticationResult.Success(authRequest.DeviceId));
  38.                      }
  39.                      else
  40.                      {
  41.                          result= result.Publish(AuthenticationResult.Failure(StatusCode.CUSTOM_ERROR, "验证失败,密码错误"));
  42.                      }
  43.                  });
  44.                return result;
  45.            }
  46.        }
复制代码
 
3.添加消息编解码代码  support.AddMessageCodecSupport(MessageTransport.Tcp, () => Observable.Return(new ScriptDeviceMessageCodec(support.Script)));, 可以自定义编解码,ScriptDeviceMessageCodec代码如下:
 
[code]using DotNetty.Buffers;using Jint;using Jint.Parser;using Microsoft.CodeAnalysis.Scripting;using Microsoft.Extensions.Logging;using RulesEngine.Models;using Surging.Core.CPlatform.Codecs.Core;using Surging.Core.CPlatform.Utilities;using Surging.Core.DeviceGateway.Runtime.Device.Message;using Surging.Core.DeviceGateway.Runtime.Device.Message.Event;using Surging.Core.DeviceGateway.Runtime.Device.Message.Property;using Surging.Core.DeviceGateway.Runtime.Device.MessageCodec;using Surging.Core.DeviceGateway.Runtime.RuleParser.Implementation;using Surging.Core.DeviceGateway.Utilities;using System;using System.Collections.Generic;using System.Linq;using System.Reactive.Linq;using System.Reactive.Subjects;using System.Runtime;using System.Text;using System.Text.Json;using System.Text.RegularExpressions;using System.Threading.Tasks;namespace Surging.Core.DeviceGateway.Runtime.Device.Implementation{    public class ScriptDeviceMessageCodec : DeviceMessageCodec    {        public string GlobalVariable { get; private set; }        public string EncoderScript { get; private set; }        public string DecoderScript { get; private set; }        public IObservable _rulePipePayload;        private readonly ILogger _logger;         public ScriptDeviceMessageCodec(string script) {            _logger = ServiceLocator.GetService();            RegexOptions options = RegexOptions.Singleline | RegexOptions.IgnoreCase;            string matchStr = Regex.Match(script, @"var\s*[\w$]*\s*\=.*function.*\(.*\)\s*\{[\s\S]*\}.*?v", options).Value;            if (!string.IsNullOrEmpty(matchStr))            {                DecoderScript = matchStr.TrimEnd('v');                DecoderScript= Regex.Replace(DecoderScript, @"var\s*[\w$]*\s*\=[.\r|\n|\t|\s]*?(function)\s*\([\w$]*\s*\)\s*\{", "", RegexOptions.IgnoreCase);                DecoderScript= DecoderScript.Slice(0, DecoderScript.LastIndexOf('}'));                EncoderScript = script.Replace(DecoderScript, "");                            }             var matchStr1 = Regex.Matches(script, @"(?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具