物联网协议Coap之C#基于Mozi的CoapServer实现解析

2024-01-19 14:20

本文主要是介绍物联网协议Coap之C#基于Mozi的CoapServer实现解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言

一、C#的Coap Server实现

1、CoapServer相关类

2、主要类解析

3、资源控制器定义 

4、ResourceManager管理器

二、CoapServer生命周期

1、Server创建代码

2、服务端创建

 3、绑定endpoint

4、准备接收请求

总结 


前言

        在之前的关于物联网协议的介绍中,我们详细介绍了如何基于Java进行Coap协议的开发,由于一些项目原因,在项目中采用的不是Java的技术栈,而是ASP.NET Core,因此需要基于C#进行Coap协议的开发与实现。Coap本身是与编程语言无关的,不仅可以用Java进行实现,当然也可以使用C#,还可以是Python、GO等多语言,感兴趣的朋友可以自行问度娘,其实每一种语言都有相应的Coap实现。以下是weixin_34026276博主分享的博客,大家可以自己熟悉的编程语言所进行的开源实现,Coap各编程语言实现传送门。非常感谢他的认真整理。

名称开发语言CoAP版本客户端/服务端实现的CoAP特征开源协议项目链接地址
CaliforniumJavaRFC 7252Client + ServerObserve, Blockwise Transfers, DTLSEPL+EDLEclipse Californium™
cantcoapC++/CRFC 7252Client + ServerBSDhttps://github.com/staropram/cantcoap
CoAP implementation for GoGoRFC 7252Client + ServerCore + Draft SubscribeMIThttps://github.com/dustin/go-coap
CoAP.NETC#RFC 7252, coap-13, coap-08, coap-03Client + ServerCore, Observe, Blockwise Transfers3-clause BSDhttps://github.com/smeshlink/CoAP.NET
CoAPSharpC#, .NETRFC 7252Client + ServerCore, Observe, Block, RDLGPLhttp://www.coapsharp.com
CoAPthonPythonRFC 7252Client + Server + Forward Proxy + Reverse ProxyObserve, Multicast server discovery, CoRE Link Format parsing, Block-wiseMIThttps://github.com/Tanganelli/CoAPthon
CopperJavaScript (Browser Plugin)RFC 7252ClientObserve, Blockwise Transfers3-clause BSDhttps://github.com/mkovatsc/Copperhttps://addons.mozilla.org/de/firefox/addon/copper-270430/
eCoAPCRFC 7252Client + ServerCoreMITjosé bollo / ecoap · GitLab
Erbium for ContikiCRFC 7252Client + ServerObserve, Blockwise Transfers3-clause BSDContiki: The Open Source Operating System for the Internet of Things (er-rest-example)
ETRI CoAPCRFC 7252Client + ServerCore, Observe, BlockCommercialhttp://coap.or.kr/index_en.html
iCoAPObjective-CRFC 7252ClientCore, Observe, Blockwise TransfersMIThttps://github.com/stuffrabbit/iCoAP
jCoAPJavaRFC 7252Client + ServerObserve, Blockwise TransfersApache License 2.0https://code.google.com/p/jcoap/
libcoapCRFC 7252Client + ServerObserve, Blockwise TransfersBSD/GPLlibcoap: C-Implementation of CoAP download | SourceForge.net
microcoapCRFC 7252Client + ServerMIThttps://github.com/1248/microcoap
nCoapJavaRFC 7252Client + ServerObserveBSDhttps://github.com/okleine/nCoAP
node-coapJavascriptRFC 7252Client + ServerCore, Observe, BlockMIThttps://github.com/mcollina/node-coap
Ruby coapRubyRFC 7252Client + Server (david)Core, Observe, Block, RDMIT, GPLhttps://github.com/nning/coap
https://github.com/nning/david
Sensinode C Device LibraryCRFC 7252Client + ServerCore, Observe, Block, RDCommercialDownloads - Arm Developer
Sensinode Java Device LibraryJava SERFC 7252Client + ServerCore, Observe, Block, RDCommercialDownloads - Arm Developer
Sensinode NanoService PlatformJava SERFC 7252Cloud ServerCore, Observe, Block, RDCommercialDownloads - Arm Developer
SMCPCRFC 7252Client + ServerCore, Observe, BlockMIThttps://github.com/darconeous/smcp
SwiftCoAPSwiftRFC 7252Client + ServerCore, Observe, Blockwise TransfersMIThttps://github.com/stuffrabbit/SwiftCoAP
TinyOS CoapBlipnesC/Ccoap-13Client + ServerObserve, Blockwise TransfersBSDhttp://docs.tinyos.net/tinywiki/index.php/CoAP
txThingsPython (Twisted)RFC 7252Client + ServerBlockwise Transfers, Observe (partial)MIThttps://github.com/siskin/txThings/

        由于对ASP.NET Core并不是很熟悉,在进行基础入门编程学习之后后,我们基于Mozi开源框架进行扩展扩展实现,这是gitee上mozi项目地址。原本的项目包含的内容比较多,我们可以在它的基础之上进行简化,改造成符合自己需求的项目。本文以CoapServer为主线,介绍CoapServer使用C#语言的定义以及后台资源管理类的定义和实现。

一、C#的Coap Server实现

        本节将重点介绍CoapServer在C#中的设计与实现,由于Coap协议在Java的篇章中有所涉及,相信大家对Coap已经不再陌生,因此这里不再对Coap进行赘述。下面依然采用熟悉的OOA即面向对象分析,采用面向对象的方式进行源代码分析。

1、CoapServer相关类

在CoapServer中,在这个工程中,主要涉及的类如下:

序号类名说明
1CoAPServerCoAP的服务端
2CoAPResource类似于Java的中controller
3ResourceManager资源管理器,可以理解成IOC容器

2、主要类解析

        CoapServer是服务端程序中最重要的类,其中主要定义了后端的服务,以及绑定了Coap协议,用于接收前端来自Client的请求。

        从类的继承体系来说,CoapServer是CoAPPeer的子类,有必要对CoAPPeer进行一个全面的说明。 

using System;
using System.Collections.Generic;
namespace Mozi.IoT
{/// <summary>/// CoAP对等端/// </summary>public class CoAPPeer{/// <summary>/// 最大数据包尺寸 包含所有头信息和有效荷载 Byte/// </summary>private int _maxTransferPackSize = 512;private int _blockSize = 128;private ulong _packetSendCount, _totalSendBytes, _packetReceived = 0, _totalReceivedBytes;protected UDPSocketIOCP _socket;protected int BindPort = CoAPProtocol.Port;/// <summary>/// 最小分块大小,单位Byte/// </summary>public const int MinBlockSize = 16;/// <summary>/// 最大分块大小,单位Byte/// </summary>public const int MaxBlockSize = 2048;/// <summary>/// 当前端默认采用块大小,默认值为128bytes,单位Byte/// </summary>/// <remarks>在通讯两方没有进行协商的情况下,默认采用此值作为分块大小。取值区间为{<see cref="MinBlockSize"/>~<see cref="MaxBlockSize"/>}</remarks>public int BlockSize { get { return _blockSize; } set { _blockSize = value; } }/// <summary>s/// 受支持的请求方法/// </summary>protected List<CoAPCode> SupportedRequest = new List<CoAPCode> { CoAPRequestMethod.Get, CoAPRequestMethod.Post, CoAPRequestMethod.Put, CoAPRequestMethod.Delete };/// <summary>/// 数据包接收事件,字节流数据包/// </summary>public PackageReceive DatagramReceived;/// <summary>/// 服务端口/// </summary>public int Port { get { return BindPort; } protected set { BindPort = value; } }/// <summary>/// 启动时间/// </summary>public DateTime StartTime { get; private set; }/// <summary>/// 服务器运行状态/// </summary>public bool Running{get; set;}/// <summary>/// 最大数据包尺寸 包含所有头信息和有效荷载/// </summary>internal int MaxTransferPackSize { get => _maxTransferPackSize; set => _maxTransferPackSize = value; }/// <summary>/// 累计接收到的包的数量/// </summary>public ulong PacketReceivedCount { get => _packetReceived; }/// <summary>/// 累计接收的字节数/// </summary>public ulong TotalReceivedBytes { get => _totalReceivedBytes; }/// <summary>/// 累计发出的包的数量/// </summary>public ulong PacketSendCount => _packetSendCount;/// <summary>                                                               /// 累计发出的字节数                                                                /// </summary>public ulong TotalSendBytes => _totalSendBytes; public CoAPPeer(){_socket = new UDPSocketIOCP();_socket.AfterReceiveEnd += Socket_AfterReceiveEnd;}/// <summary>/// 以指定端口启动<see cref="F:Port"/>,如果不配置端口则使用默认端口/// </summary>public void Start(){Start(BindPort);}/// <summary>/// 启动本端服务 默认5683端口/// </summary>/// <param name="port"></param>public void Start(int port){BindPort = port;_socket.Start(BindPort);StartTime = DateTime.Now;Running = true;}/// <summary>/// 端口下线/// </summary>public void Shutdown(){_socket.Shutdown();StartTime = DateTime.MinValue;Running = false;}/// <summary>/// 数据接收完成回调/// </summary>/// <param name="sender"></param>/// <param name="args"></param>/// <remarks>继承类如果覆盖该事件,则可以接管数据处理</remarks>protected virtual void Socket_AfterReceiveEnd(object sender, DataTransferArgs args){_packetReceived++;_totalReceivedBytes += args.Data != null ? (uint)args.Data.Length : 0;if (DatagramReceived != null){DatagramReceived(args.IP, args.Port, args.Data);}}}
}

         从以上的代码中可以发现,上述类也是定义了CoAP协议工作所必须要的一些属性,比如端口、协议、数据包内容等等。CoapServer的属性代码如下:

 private Cache.MessageCacheManager _cm;/// <summary>
/// 接收到请求
/// </summary>
public MessageTransmit RequestReceived;
/// <summary>
/// 发起响应请求
/// </summary>
public MessageTransmit Responsed;
private bool _proxyPassed = false;
private uint maxBodySize=20*1024*1024;
/// <summary>
/// 服务端能处理的最大POST资源大小 单位byte
/// </summary>
public uint MaxBodySize { get => maxBodySize; set => maxBodySize = value; }
/// <summary>
/// 服务器根目录
/// </summary>
public string Root = AppDomain.CurrentDomain.BaseDirectory;

3、资源控制器定义 

每一个后台都会对应一个资源控制器,这里也不例外,我们来看下C#的实现。在CoapResource中同样的定义了get、post、put、delete四种请求方法。如下图所示:

/// <summary>/// CoAP资源/// </summary>public abstract class CoAPResource{/// <summary>/// 资源总大小/// </summary>public abstract uint ResourceSize { get; }/// <summary>/// 默认分块大小128,单位Bytes /// </summary>/// <remarks>/// 如果资源尺寸过大,则必须合理配置此大小。/// 取值范围为16-2048Bytes BlockOptionValue中Size的数据容量。参考<see cref="BlockOptionValue"/>/// </remarks>public virtual uint BlockSize { get { return 128; } }/// <summary>/// GET方法/// </summary>/// <param name="ctx"></param>/// <returns></returns>public virtual CoAPPackage OnGet(CoAPContext ctx){ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Forbidden };return ctx.Response;}/// <summary>/// Post方法/// </summary>/// <param name="ctx"></param>/// <returns></returns>public virtual CoAPPackage OnPost(CoAPContext ctx){ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Forbidden };return ctx.Response;}/// <summary>/// PUT方法/// </summary>/// <param name="ctx"></param>/// <returns></returns>public virtual CoAPPackage OnPut(CoAPContext ctx){ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Forbidden };return ctx.Response;}/// <summary>/// Delete方法/// </summary>/// <param name="ctx"></param>/// <returns></returns>public virtual CoAPPackage OnDelete(CoAPContext ctx){ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Forbidden };return ctx.Response;}/// <summary>/// 分块查找/// </summary>/// <param name="indBlock"></param>/// <param name="blockSize"></param>/// <returns></returns>protected virtual byte[] Seek(int indBlock, int blockSize){return new byte[] { };}/// <summary>/// Block2分块协商/// </summary>/// <param name="ctx"></param>/// <returns></returns>internal virtual void HandleBlock2Query(CoAPContext ctx){CoAPOption opt = ctx.Request.Options.Find(x => x.Option == CoAPOptionDefine.Block2);if (opt != null){OptionValue opt2 = new BlockOptionValue() { Pack = opt.Value.Pack };//if(opt2)}}/// <summary>/// 请求服务端资源大小,响应条件为 Get Size2=0/// </summary>/// <param name="ctx">响应上下文对象</param>/// <returns></returns>internal virtual bool HandleSize2Query(CoAPContext ctx){CoAPOption opt = ctx.Request.Options.Find(x => x.Option == CoAPOptionDefine.Size2);if (opt != null && int.Parse(opt.Value.ToString()) ==0 && ctx.Request.Code == CoAPRequestMethod.Get){ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Content };CoAPOption optResp = new CoAPOption() { Option = CoAPOptionDefine.Size2, Value = new UnsignedIntegerOptionValue() { Value = ResourceSize } };ctx.Response.SetOption(optResp);return true;}else{return false;}}}

4、ResourceManager管理器

        每个业务接收类都对应一个Resource,而这些Resource必须要使用一个统一的容器管理起来,可以把它理解成Java对应的IOC容器,程序运行时会自动把相关资源管理起来。资源描述如下

 public class ResourceDescriptionAttribute : Attribute{/// <summary>/// 命名空间/// </summary>public string Namespace { get; set; }/// <summary>/// 资源名称/// </summary>public string Name { get; set; }/// <summary>/// 文字描述/// </summary>public string Description { get; set; }/// <summary>/// 资源类型/// </summary>public string ResourceType { get; set; }}

        资源管理器的核心管理方式也是采用反射的机制,如下:

二、CoapServer生命周期

        在上面的代码中,对CoapServer的编码实现进行了介绍,下面将采用熟悉的调试方法来进行调用跟踪,在关键代码中进行深度讲解。

1、Server创建代码

        创建Server的代码如下:

static void Main(string[] args){Console.WriteLine("你好!COAP服务端已开启,等待客户端连接......");//服务端CoAPServer cs = new CoAPServer();cs.RequestReceived += new MessageTransmit((host, port, pack) =>{Console.WriteLine($"From:[{host}:{port}]");Console.WriteLine(pack.ToString());Console.Title = string.Format("elapsed:{2},count:{0},pps:{3},bytes:{1}", cs.PacketReceivedCount, cs.TotalReceivedBytes,FormatSeconds(sp.ElapsedMilliseconds),pps);});cs.Start();Console.ReadLine();}

2、服务端创建

        第一步、调用构造方法

        第二步、指定端口启动

 第三步、设置socket,绑定协议

 3、绑定endpoint

4、准备接收请求

 

总结 

        以上就是本文的主要内容,本文以CoapServer为主线,介绍CoapServer使用C#语言的定义以及后台资源管理类的定义和实现。行文仓促,定有不当之处,欢迎各位朋友专家批评指正。

这篇关于物联网协议Coap之C#基于Mozi的CoapServer实现解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/622701

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

详解C#如何提取PDF文档中的图片

《详解C#如何提取PDF文档中的图片》提取图片可以将这些图像资源进行单独保存,方便后续在不同的项目中使用,下面我们就来看看如何使用C#通过代码从PDF文档中提取图片吧... 当 PDF 文件中包含有价值的图片,如艺术画作、设计素材、报告图表等,提取图片可以将这些图像资源进行单独保存,方便后续在不同的项目中使

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面