当前位置:   article > 正文

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

c# coap 协议

目录

前言

一、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进行一个全面的说明。 

  1. using System;
  2. using System.Collections.Generic;
  3. namespace Mozi.IoT
  4. {
  5. /// <summary>
  6. /// CoAP对等端
  7. /// </summary>
  8. public class CoAPPeer
  9. {
  10. /// <summary>
  11. /// 最大数据包尺寸 包含所有头信息和有效荷载 Byte
  12. /// </summary>
  13. private int _maxTransferPackSize = 512;
  14. private int _blockSize = 128;
  15. private ulong _packetSendCount, _totalSendBytes, _packetReceived = 0, _totalReceivedBytes;
  16. protected UDPSocketIOCP _socket;
  17. protected int BindPort = CoAPProtocol.Port;
  18. /// <summary>
  19. /// 最小分块大小,单位Byte
  20. /// </summary>
  21. public const int MinBlockSize = 16;
  22. /// <summary>
  23. /// 最大分块大小,单位Byte
  24. /// </summary>
  25. public const int MaxBlockSize = 2048;
  26. /// <summary>
  27. /// 当前端默认采用块大小,默认值为128bytes,单位Byte
  28. /// </summary>
  29. /// <remarks>在通讯两方没有进行协商的情况下,默认采用此值作为分块大小。取值区间为{<see cref="MinBlockSize"/>~<see cref="MaxBlockSize"/>}</remarks>
  30. public int BlockSize { get { return _blockSize; } set { _blockSize = value; } }
  31. /// <summary>s
  32. /// 受支持的请求方法
  33. /// </summary>
  34. protected List<CoAPCode> SupportedRequest = new List<CoAPCode> { CoAPRequestMethod.Get, CoAPRequestMethod.Post, CoAPRequestMethod.Put, CoAPRequestMethod.Delete };
  35. /// <summary>
  36. /// 数据包接收事件,字节流数据包
  37. /// </summary>
  38. public PackageReceive DatagramReceived;
  39. /// <summary>
  40. /// 服务端口
  41. /// </summary>
  42. public int Port { get { return BindPort; } protected set { BindPort = value; } }
  43. /// <summary>
  44. /// 启动时间
  45. /// </summary>
  46. public DateTime StartTime { get; private set; }
  47. /// <summary>
  48. /// 服务器运行状态
  49. /// </summary>
  50. public bool Running
  51. {
  52. get; set;
  53. }
  54. /// <summary>
  55. /// 最大数据包尺寸 包含所有头信息和有效荷载
  56. /// </summary>
  57. internal int MaxTransferPackSize { get => _maxTransferPackSize; set => _maxTransferPackSize = value; }
  58. /// <summary>
  59. /// 累计接收到的包的数量
  60. /// </summary>
  61. public ulong PacketReceivedCount { get => _packetReceived; }
  62. /// <summary>
  63. /// 累计接收的字节数
  64. /// </summary>
  65. public ulong TotalReceivedBytes { get => _totalReceivedBytes; }
  66. /// <summary>
  67. /// 累计发出的包的数量
  68. /// </summary>
  69. public ulong PacketSendCount => _packetSendCount;
  70. /// <summary>
  71. /// 累计发出的字节数
  72. /// </summary>
  73. public ulong TotalSendBytes => _totalSendBytes;
  74. public CoAPPeer()
  75. {
  76. _socket = new UDPSocketIOCP();
  77. _socket.AfterReceiveEnd += Socket_AfterReceiveEnd;
  78. }
  79. /// <summary>
  80. /// 以指定端口启动<see cref="F:Port"/>,如果不配置端口则使用默认端口
  81. /// </summary>
  82. public void Start()
  83. {
  84. Start(BindPort);
  85. }
  86. /// <summary>
  87. /// 启动本端服务 默认5683端口
  88. /// </summary>
  89. /// <param name="port"></param>
  90. public void Start(int port)
  91. {
  92. BindPort = port;
  93. _socket.Start(BindPort);
  94. StartTime = DateTime.Now;
  95. Running = true;
  96. }
  97. /// <summary>
  98. /// 端口下线
  99. /// </summary>
  100. public void Shutdown()
  101. {
  102. _socket.Shutdown();
  103. StartTime = DateTime.MinValue;
  104. Running = false;
  105. }
  106. /// <summary>
  107. /// 数据接收完成回调
  108. /// </summary>
  109. /// <param name="sender"></param>
  110. /// <param name="args"></param>
  111. /// <remarks>继承类如果覆盖该事件,则可以接管数据处理</remarks>
  112. protected virtual void Socket_AfterReceiveEnd(object sender, DataTransferArgs args)
  113. {
  114. _packetReceived++;
  115. _totalReceivedBytes += args.Data != null ? (uint)args.Data.Length : 0;
  116. if (DatagramReceived != null)
  117. {
  118. DatagramReceived(args.IP, args.Port, args.Data);
  119. }
  120. }
  121. }
  122. }

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

  1. private Cache.MessageCacheManager _cm;
  2. /// <summary>
  3. /// 接收到请求
  4. /// </summary>
  5. public MessageTransmit RequestReceived;
  6. /// <summary>
  7. /// 发起响应请求
  8. /// </summary>
  9. public MessageTransmit Responsed;
  10. private bool _proxyPassed = false;
  11. private uint maxBodySize=20*1024*1024;
  12. /// <summary>
  13. /// 服务端能处理的最大POST资源大小 单位byte
  14. /// </summary>
  15. public uint MaxBodySize { get => maxBodySize; set => maxBodySize = value; }
  16. /// <summary>
  17. /// 服务器根目录
  18. /// </summary>
  19. public string Root = AppDomain.CurrentDomain.BaseDirectory;

3、资源控制器定义 

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

  1. /// <summary>
  2. /// CoAP资源
  3. /// </summary>
  4. public abstract class CoAPResource
  5. {
  6. /// <summary>
  7. /// 资源总大小
  8. /// </summary>
  9. public abstract uint ResourceSize { get; }
  10. /// <summary>
  11. /// 默认分块大小128,单位Bytes
  12. /// </summary>
  13. /// <remarks>
  14. /// 如果资源尺寸过大,则必须合理配置此大小。
  15. /// 取值范围为16-2048Bytes BlockOptionValue中Size的数据容量。参考<see cref="BlockOptionValue"/>
  16. /// </remarks>
  17. public virtual uint BlockSize { get { return 128; } }
  18. /// <summary>
  19. /// GET方法
  20. /// </summary>
  21. /// <param name="ctx"></param>
  22. /// <returns></returns>
  23. public virtual CoAPPackage OnGet(CoAPContext ctx)
  24. {
  25. ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Forbidden };
  26. return ctx.Response;
  27. }
  28. /// <summary>
  29. /// Post方法
  30. /// </summary>
  31. /// <param name="ctx"></param>
  32. /// <returns></returns>
  33. public virtual CoAPPackage OnPost(CoAPContext ctx)
  34. {
  35. ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Forbidden };
  36. return ctx.Response;
  37. }
  38. /// <summary>
  39. /// PUT方法
  40. /// </summary>
  41. /// <param name="ctx"></param>
  42. /// <returns></returns>
  43. public virtual CoAPPackage OnPut(CoAPContext ctx)
  44. {
  45. ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Forbidden };
  46. return ctx.Response;
  47. }
  48. /// <summary>
  49. /// Delete方法
  50. /// </summary>
  51. /// <param name="ctx"></param>
  52. /// <returns></returns>
  53. public virtual CoAPPackage OnDelete(CoAPContext ctx)
  54. {
  55. ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Forbidden };
  56. return ctx.Response;
  57. }
  58. /// <summary>
  59. /// 分块查找
  60. /// </summary>
  61. /// <param name="indBlock"></param>
  62. /// <param name="blockSize"></param>
  63. /// <returns></returns>
  64. protected virtual byte[] Seek(int indBlock, int blockSize)
  65. {
  66. return new byte[] { };
  67. }
  68. /// <summary>
  69. /// Block2分块协商
  70. /// </summary>
  71. /// <param name="ctx"></param>
  72. /// <returns></returns>
  73. internal virtual void HandleBlock2Query(CoAPContext ctx)
  74. {
  75. CoAPOption opt = ctx.Request.Options.Find(x => x.Option == CoAPOptionDefine.Block2);
  76. if (opt != null)
  77. {
  78. OptionValue opt2 = new BlockOptionValue() { Pack = opt.Value.Pack };
  79. //if(opt2)
  80. }
  81. }
  82. /// <summary>
  83. /// 请求服务端资源大小,响应条件为 Get Size2=0
  84. /// </summary>
  85. /// <param name="ctx">响应上下文对象</param>
  86. /// <returns></returns>
  87. internal virtual bool HandleSize2Query(CoAPContext ctx)
  88. {
  89. CoAPOption opt = ctx.Request.Options.Find(x => x.Option == CoAPOptionDefine.Size2);
  90. if (opt != null && int.Parse(opt.Value.ToString()) ==0 && ctx.Request.Code == CoAPRequestMethod.Get)
  91. {
  92. ctx.Response = new CoAPPackage { MessageType = CoAPMessageType.Acknowledgement, MesssageId = ctx.Request.MesssageId, Token = ctx.Request.Token, Code = CoAPResponseCode.Content };
  93. CoAPOption optResp = new CoAPOption() { Option = CoAPOptionDefine.Size2, Value = new UnsignedIntegerOptionValue() { Value = ResourceSize } };
  94. ctx.Response.SetOption(optResp);
  95. return true;
  96. }
  97. else
  98. {
  99. return false;
  100. }
  101. }
  102. }

4、ResourceManager管理器

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

  1. public class ResourceDescriptionAttribute : Attribute
  2. {
  3. /// <summary>
  4. /// 命名空间
  5. /// </summary>
  6. public string Namespace { get; set; }
  7. /// <summary>
  8. /// 资源名称
  9. /// </summary>
  10. public string Name { get; set; }
  11. /// <summary>
  12. /// 文字描述
  13. /// </summary>
  14. public string Description { get; set; }
  15. /// <summary>
  16. /// 资源类型
  17. /// </summary>
  18. public string ResourceType { get; set; }
  19. }

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

二、CoapServer生命周期

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

1、Server创建代码

        创建Server的代码如下:

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

2、服务端创建

        第一步、调用构造方法

        第二步、指定端口启动

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

 3、绑定endpoint

4、准备接收请求

 

总结 

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/article/detail/82853
推荐阅读
相关标签
  

闽ICP备14008679号