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

ModbusFunction 类图如下:

如前文所述,所有请求/相应的 PDU 均继承自 ModbusFunction,其子类传入对应的 Function Code 并实现三个方法:

  1. CalculateLength:Data 部分的长度(该方法也可以为属性,但属性没有强制性,怕漏掉故改为抽象方法)
  2. Decode:从缓冲区解析 Data
  3. Encode:在传输前对 Data 编码

实现举例

每个 Function Code 均对应 ModbusFunction 的两个子类:请求类和响应类,以 0x03(读取保持寄存器值)为例:

请求类

请求报文 Data 说明:

public class ReadHoldingRegistersRequest : ModbusFunction
{
public ushort StartingAddress { get; private set; }
public ushort Quantity { get; private set; } public ReadHoldingRegistersRequest()
: base((short)ModbusCommand.ReadHoldingRegisters)
{ } public ReadHoldingRegistersRequest(ushort startingAddress, ushort quantity)
: base((short)ModbusCommand.ReadHoldingRegisters)
{
StartingAddress = startingAddress;
Quantity = quantity;
} public override int CalculateLength()
{
return 2 + 2; // StartingAddress Length + Quantity Length
}
public override void Decode(IByteBuffer buffer)
{
StartingAddress = buffer.ReadUnsignedShort();
Quantity = buffer.ReadUnsignedShort();
}
public override IByteBuffer Encode()
{
IByteBuffer buffer = Unpooled.Buffer();
buffer.WriteByte(FunctionCode); buffer.WriteUnsignedShort(StartingAddress);
buffer.WriteUnsignedShort(Quantity); return buffer;
}
}

响应类

响应报文 Data 说明:

public class ReadHoldingRegistersResponse : ModbusFunction
{
private ushort byteCount;
public ushort[] Registers { get; private set; } public ReadHoldingRegistersResponse()
: base((short)ModbusCommand.ReadHoldingRegisters)
{ } public ReadHoldingRegistersResponse(ushort[] registers)
: base((short)ModbusCommand.ReadHoldingRegisters)
{
Registers = registers;
byteCount = (ushort)(registers.Length * 2);
} public override int CalculateLength()
{
return 1 + byteCount;
} public override void Decode(IByteBuffer buffer)
{
byteCount = buffer.ReadByte();
Registers = new ushort[byteCount / 2];
for (int i = 0; i < Registers.Length; i++)
{
Registers[i] = buffer.ReadUnsignedShort();
} } public override IByteBuffer Encode()
{
IByteBuffer buffer = Unpooled.Buffer();
buffer.WriteByte(FunctionCode);
buffer.WriteByte(byteCount); foreach (var register in Registers)
{
buffer.WriteUnsignedShort(register);
} return buffer;
}
}

其中 ModbusCommand 为 Function Code 的枚举:

enum ModbusCommand : short
{ ReadCoils = 0x01,
ReadDiscreteInputs = 0x02,
ReadHoldingRegisters = 0x03,
ReadInputRegisters = 0x04,
WriteSingleCoil = 0x05,
WriteSingleRegister = 0x06, WriteMultipleCoils = 0x0F,
WriteMultipleRegisters = 0x10, }

文中为方便理解请求类和响应类均直接继承 ModbusFunction,实际开发中请求类和响应类均没有直接继承 ModbusFunction,而是根据其他 Function Code 的 Data 进行再次抽象后继承。

开源地址:modbus-tcp

DotNetty 实现 Modbus TCP 系列 (二) ModbusFunction 类图及继承举例的更多相关文章

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

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

  2. DotNetty 实现 Modbus TCP 系列 (三) Codecs & Handler

    本文已收录至:开源 DotNetty 实现的 Modbus TCP/IP 协议 DotNetty 作为一个半成品,我们不需要关注细节的实现,只需要关注自己的业务即可,所以最主要的就是处理 Codecs ...

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

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

  4. c/c++ 模板与STL小例子系列<二> 模板类与友元函数

    c/c++ 模板与STL小例子系列 模板类与友元函数 比如某个类是个模板类D,有个需求是需要重载D的operator<<函数,这时就需要用到友元. 实现这样的友元需要3个必要步骤 1,在模 ...

  5. UML学习(二)-----类图

    UML学习(二)-----类图 http://www.cnblogs.com/silent2012/archive/2011/09/07/2169946.html http://www.cnblogs ...

  6. 转载:UML学习(二)-----类图(silent)

    原文:http://www.cnblogs.com/huiy/p/8552607.html 1.什么是类图 类图(Class diagram)主要用于描述系统的结构化设计.类图也是最常用的UML图,用 ...

  7. UML类图关系(继承、泛化、实现、依赖、关联、聚合、组合)

    继承.实现.依赖.关联.聚合.组合的联系与区别 分别介绍这几种关系: 继承 指的是一个类(称为子类.子接口)继承另外的一个类(称为父类.父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者 ...

  8. UML类图关系--继承(泛化)、实现、关联、聚合、组合、依赖

    在UML类图中,常见的有以下几种关系:  泛化(Generalization),  实现(Realization),关联(Association),聚合(Aggregation),组合(Composi ...

  9. Java多线程系列二——Thread类的方法

    Thread实现Runnable接口并实现了大量实用的方法 public static native void yield(); 此方法释放CPU,但并不释放已获得的锁,其它就绪的线程将可能得到执行机 ...

随机推荐

  1. redis list 清空记录小技巧

    redis list 清空记录小技巧   redis中的list操作命令中删除指定key中的所有记录命令: ltrim key 1 0 即 ltrim key start end 中的start要比e ...

  2. Apollo内核版本安装

    参考:https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/apollo_software_installation_gui ...

  3. mac sourcetree push分支选中所有tag的时候报错

    错误信息: ....... ! [rejected] 573_0811_stable -> 573_0811_stable (already exists)updating local trac ...

  4. Linux内存管理之mmap详解

    转发之:http://blog.chinaunix.net/uid-26669729-id-3077015.html Linux内存管理之mmap详解 一. mmap系统调用 1. mmap系统调用  ...

  5. Vue-校验props传来的值

    对父组件传来的值进行校验. Vue.component('child',{ props:{ content:{ type:String, required:false, default:'li zha ...

  6. 图解Redis之数据结构篇——字典

    前言     字典在Redis中的应用非常广泛,数据库与哈希对象的底层实现就是字典. 系列文章 图解Redis之数据结构篇--简单动态字符串SDS 图解Redis之数据结构篇--链表 图解Redis之 ...

  7. iOS开发简记(5):设备唯一标识与全局变量

    这里记录两个iOS开发中经常用到的知识点,一个是唯一标识,一个是全局变量. (1)唯一标识 唯一标识一台设备(比如iPhone.iPad等)是一个基本的实现与业务上的需求,因为这个唯一标识在许多场景都 ...

  8. MyBatis + MySQL返回插入成功后的主键id

    这是最近在实现perfect-ssm中的一个功能时碰到的一个小问题,觉得需要记录一下,向MySQL数据库中插入一条记录后,需要获取此条记录的id值,以生成对应的key值存入到redis中,id为自增i ...

  9. Spring如何加载log4j配置文件

    今天有朋友在群里问了这个问题,于是写了这篇文章进行整理. 问题如下: 在项目中添加了log4j.properties配置文件,并没有在Spring配置文件中配置,也没有在web.xml中配置,但是代码 ...

  10. Taro、Weex、Hippy 齐聚IMWebConf 2018!

    IMWebConf 2018 前端大会,10 月 14 日重磅来袭! 想了解 2018 前端前沿技术和发展趋势?想挖掘前端更深远的价值?就在这个秋季,第七届 IMWebConf 大会重磅来袭,我们邀请 ...