本文已收录至:开源 DotNetty 实现的 Modbus TCP/IP 协议

DotNetty 作为一个半成品,我们不需要关注细节的实现,只需要关注自己的业务即可,所以最主要的就是处理 Codecs 和 Handler。

所有的 Codecs 和 Handler 均直接或间接继承自 ChannelHandlerAdapter。为什么要分为 Codecs 和 Handler,个人理解是 Codecs 负责将消息解码为我们所需的对象或者将处理的结果编码,Handler 对解码得到的对象进行逻辑处理,达到职责分离的目的。

DotNetty 中可以注册多个 Codecs/Handler,入站消息按照注册的先后顺序执行,出站消息按照注册的先后逆序执行。

对于 Client 端:

  • 入站:ModbusDecoder --> ModbusResponseHandler
  • 出站:ModbusEncoder

对于 Server 端:

  • 入站:ModbusDecoder --> ModbusRequestHandler
  • 出站:ModbusEncoder

ModbusDecoder

public class ModbusDecoder : ByteToMessageDecoder
{
private bool isServerMode;
private readonly short maxFunctionCode = 0x80;
private readonly string typeName = "Karonda.ModbusTcp.Entity.Function.{0}.{1}{0}"; public ModbusDecoder(bool isServerMode)
{
this.isServerMode = isServerMode;
}
protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output)
{
//Transaction Identifier + Protocol Identifier + Length + Unit Identifier + Function Code
if (input.Capacity < 2 + 2 + 2 + 1 + 1)
{
return;
} ModbusHeader header = new ModbusHeader(input);
short functionCode = input.ReadByte();
ModbusFunction function = null; if(Enum.IsDefined(typeof(ModbusCommand), functionCode))
{
var command = Enum.GetName(typeof(ModbusCommand), functionCode); function = (ModbusFunction)Activator.CreateInstance(Type.GetType(string.Format(typeName, isServerMode ? "Request" : "Response", command)));
} if (functionCode >= maxFunctionCode)
{
function = new ExceptionFunction(functionCode);
}
else if(function == null)
{
function = new ExceptionFunction(functionCode, 0x01);
} function.Decode(input);
ModbusFrame frame = new ModbusFrame(header, function); output.Add(frame);
}
}

ModbusDecoder 继承了 ByteToMessageDecoder。继承了 ByteToMessageDecoder 的类必须实现的唯一的抽象方法:Decode,该方法将 ByteBuffer 解析为 List,如果 List 不为空则会将该 List 传递给下一个 ChannelHandlerAdapter。

ModbusDecoder 同时为 Client 端和 Server 端使用,如果是 Server 端则将消息解析成请求类,反之如果是 Client 端则将消息解析成响应类。

ModbusResponseHandler

public class ModbusResponseHandler : SimpleChannelInboundHandler<ModbusFrame>
{
private Dictionary<ushort, ModbusFrame> responses = new Dictionary<ushort, ModbusFrame>();
protected override void ChannelRead0(IChannelHandlerContext ctx, ModbusFrame msg)
{
responses.Add(msg.Header.TransactionIdentifier, msg);
} public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
{
context.CloseAsync();
}
}

将接收到的响应信息加入 responses 供后续处理。

ModbusRequestHandler

public class ModbusRequestHandler : SimpleChannelInboundHandler<ModbusFrame>
{
private ModbusResponseService responseService;
public ModbusRequestHandler(ModbusResponseService responseService)
{
this.responseService = responseService;
} protected override void ChannelRead0(IChannelHandlerContext ctx, ModbusFrame msg)
{
var function = msg.Function;
var response = responseService.Execute(function); var header = msg.Header;
var frame = new ModbusFrame(header, response); ctx.WriteAndFlushAsync(frame);
}
}

responseService 为一个抽象类,用来自定义处理接收到的请求并返回结果,需要在实现 Server 端时继承并实现。

public abstract class ModbusResponseService
{
public ModbusFunction Execute(ModbusFunction function)
{
if (function is ReadHoldingRegistersRequest)
{
var request = (ReadHoldingRegistersRequest)function;
return ReadHoldingRegisters(request);
} throw new Exception("Function Not Support");
} public abstract ModbusFunction ReadHoldingRegisters(ReadHoldingRegistersRequest request);
}

(文中代码仅添加了 0x03 的方法)

ModbusEncoder

public class ModbusEncoder : ChannelHandlerAdapter
{
public override Task WriteAsync(IChannelHandlerContext context, object message)
{
if (message is ModbusFrame)
{
var frame = (ModbusFrame)message;
return context.WriteAndFlushAsync(frame.Encode());
} return context.WriteAsync(message);
}
}

如果是 ModbusFrame 消息则 Flush,否则传递到下一个 ChannelHandlerAdapter。

开源地址:modbus-tcp

DotNetty 实现 Modbus TCP 系列 (三) Codecs & Handler的更多相关文章

  1. DotNetty 实现 Modbus TCP 系列 (四) Client & Server

    本文已收录至:开源 DotNetty 实现的 Modbus TCP/IP 协议 Client public class ModbusClient { public string Ip { get; } ...

  2. DotNetty 实现 Modbus TCP 系列 (二) ModbusFunction 类图及继承举例

    本文已收录至:开源 DotNetty 实现的 Modbus TCP/IP 协议 ModbusFunction 类图如下: 如前文所述,所有请求/相应的 PDU 均继承自 ModbusFunction, ...

  3. DotNetty 实现 Modbus TCP 系列 (一) 报文类

    本文已收录至:开源 DotNetty 实现的 Modbus TCP/IP 协议 Modbus TCP/IP 报文 报文最大长度为 260 byte (ADU = 7 byte MBAP Header ...

  4. 开源 DotNetty 实现的 Modbus TCP/IP 协议

    本项目的目的是为了学习 DotNetty 与 Modbus 协议,参考 modjn 实现功能 0x01: Read Coils (读取线圈/离散量输出状态) 0x02: Read Discrete I ...

  5. 开放型Modbus/TCP 规范

    修订版 1.0,1999 年3 月29 日Andy SwalesSchneider 电气公司aswales@modicon.com目录目录............................... ...

  6. 基于STM32和W5500的Modbus TCP通讯

    在最近的一个项目中需要实现Modbus TCP通讯,而选用的硬件平台则是STM32F103和W5500,软件平台则选用IAR EWAR6.4来实现. 1.移植千的准备工作 为了实现Modbus TCP ...

  7. WCF编程系列(三)地址与绑定

    WCF编程系列(三)地址与绑定   地址     地址指定了接收消息的位置,WCF中地址以统一资源标识符(URI)的形式指定.URI由通讯协议和位置路径两部分组成,如示例一中的: http://loc ...

  8. mybatis入门系列三之类型转换器

    mybatis入门系列三之类型转换器 类型转换器介绍 mybatis作为一个ORM框架,要求java中的对象与数据库中的表记录应该对应 因此java类名-数据库表名,java类属性名-数据库表字段名, ...

  9. ldap配置系列三:grafana集成ldap

    ldap配置系列三:grafana集成ldap grafana的简介 grafana是一个类似kibana的东西,是对来自各种数据源的数据进行实时展示的平台,拥有这牛逼的外观.给一个官方的demo体验 ...

随机推荐

  1. 在DreamView中支持一辆新车

    Support a new Vehicle in DreamView In order to support a new vehicle in DreamView, please follow the ...

  2. 【Codeforces 339】Xenia and Bit Operations

    Codeforces 339 D 题意:给定\(2^n​\)个数字,现在把它们进行如下操作: 相邻的两个数取\(or\) 相邻的两个数取\(xor\) 以此类推,直到剩下一个数. 问每次修改一个数字, ...

  3. [TPYBoard - Micropython之会python就能做硬件 1] 运行第一个脚本——点亮LED

    转载请注明:@小五义http://www.cnblogs.com/xiaowuyiQQ群:64770604 会python就能做硬件! 一.TPYBoard V102开发板 TPYBoard V102 ...

  4. C# 下载文件

    最近一段时间,真的是太忙太忙了!经历了自我毕业以来最忙碌的一个项目! 说起这个项目,我有万千感慨 且不说技术能力,也无需谈论项目需求.单就项目压力,日常加班,周六日补班而言,我相信很多人是扛不住的! ...

  5. Asp.net MVC 利用(aspose+pdfobject.js) 实现在线预览word、excel、ppt、pdf文件

    在线预览word.excel.ppt利用aspose动态生成html 主要代码 private bool OfficeDocumentToHtml(string sourceDoc, string s ...

  6. JavaScript原生秒表、计时器

    可以开始.暂停.清除. 效果图: 下面贴代码: <!DOCTYPE html> <html lang="en"> <head> <meta ...

  7. .Net高级进阶,教你如何构建企业模型数据拦截层,动态控制字段验证

    现在,你有一个MVC架构的web项目,你要完成一个注册功能. 前台传了3个值到你的控制器,分别是账号.密码.邮箱. 如图:现在你要在控制器里面判断,账号名称.密码.邮箱不能为空,并且名称和密码不超过1 ...

  8. 【NLP】Attention Model(注意力模型)学习总结

    最近一直在研究深度语义匹配算法,搭建了个模型,跑起来效果并不是很理想,在分析原因的过程中,发现注意力模型在解决这个问题上还是很有帮助的,所以花了两天研究了一下. 此文大部分参考深度学习中的注意力机制( ...

  9. NLP是什么

    NLP是什么 而在计算机领域, NLP(Natural Language Processing),也就是人们常说的「自然语言处理」,就是研究如何让计算机读懂人类语言. 这包括,既要能让计算机理解自然语 ...

  10. 一次linux服务器黑客入侵后处理

     场景: 周一上班centos服务器ssh不可用,web和数据库等应用不响应.好在vnc可以登录 使用last命令查询,2号之前的登录信息已被清空,并且sshd文件在周六晚上被修改,周日晚上2点服务器 ...