当前位置: 代码网 > it编程>编程语言>Asp.net > 物联网协议Coap之C#基于Mozi的CoapServer实现解析

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

2024年08月06日 Asp.net 我要评论
本文以CoapServer为主线,介绍CoapServer使用C#语言的定义以及后台资源管理类的定义和实现。

目录

前言

一、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实现。以下是博主分享的博客,大家可以自己熟悉的编程语言所进行的开源实现,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#语言的定义以及后台资源管理类的定义和实现。行文仓促,定有不当之处,欢迎各位朋友专家批评指正。

(0)

相关文章:

  • 【深入浅出C#】文件和输入输出操作:文件读写和流操作

    【深入浅出C#】文件和输入输出操作:文件读写和流操作

    在计算机编程中,文件读写和流操作是非常重要的主题。文件读写允许我们将数据存储到文件中或从文件中读取数据,是持久化数据的常见方式。在C#中,我们可以使用文件流来进... [阅读全文]
  • C#编写Socket服务器

    由Socket慨念,Socket一般应用模式,Socket的通讯过程,再逐步深入到项目界面设计,程序编码,叫你一步步实现用C#编写Socket服务器,代码全部都有注释。…

    2024年08月06日 编程语言
  • 基于C#的上位机开发第一期:S7.NET

    的的判断可以帮助我门在变量值改变时才启动数据转化操作,如果没有这种判断会损耗性能,加大程序的工作量。Rack:它包含PLC 的机架,您可以在 Step7 的硬件配置中找到该机架,可…

    2024年08月06日 编程语言
  • 记录|C# winform布局学习

    记录|C# winform布局学习

    C#5分钟winform快速自适应布局参考文章:其他参考:写这篇文章,主要是我发现自己的界面太丑了,我受不了。而且项目运行后,winform窗口是窗口,放大后又... [阅读全文]
  • c#引入nuget包到本地

    c#引入nuget包到本地

    当你在C#项目中引用了外部库或NuGet包时,这些依赖项通常会被下载到本地的NuGet缓存(通常是用户的个人文件夹中的.nuget/packages目录),而不... [阅读全文]
  • C# 基于Quartz.Net实现定时任务

    C# 基于Quartz.Net实现定时任务

    大家好,我是不自由的小码,这次要给大家分享的是基于Quartz.Net实现定时任务。timer这个东西相信大家都不会陌生,然而,timer的局限性,注定了在复杂... [阅读全文]

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com