本文已收录至:开源 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. __attribute__ 机制详解(一)

    GNU C 的一大特色就是__attribute__ 机制.__attribute__ 可以设置函数属性(Function Attribute).变量属性(Variable Attribute)和类型 ...

  2. KakfaSpout自定义scheme

    一.Mapper和Scheme scheme:将kafka传到spout里的数据格式进行转化. record->tuple mapper:将storm传到kafka的数据格式进行转化.tuple ...

  3. Maven之profile实现多环境配置动态切换

            一般的软件项目,在开发.测试及生产等环境下配置文件中参数是不同的.传统的做法是在项目部署的时候,手动修改或者替换这个配置文件.这样太麻烦了,我们可以用Maven的profile来解决这 ...

  4. JVM规范系列开篇:为什么要读JVM规范?

    许多人知道类加载机制.JVM内存模型,但他们可能不知道什么是<Java虚拟机规范>.对于Java开发来说,<Java虚拟机规范>才是最为官方.准确的一个文档,了解这个规范可以让 ...

  5. 使用PHPExcel将数据导出至Excel

    安装类库 从GitHub上下载PHPExcel类库 地址:https://github.com/PHPOffice/PHPExcel 解压后将Classes文件夹移动到ThinkPHP的extend目 ...

  6. 通过 Systemd Journal 收集日志

    随着 systemd 成了主流的 init 系统,systemd 的功能也在不断的增加,比如对系统日志的管理.Systemd 设计的日志系统好处多多,这里笔者就不再赘述了,本文笔者主要介绍 syste ...

  7. android linux 传文件

    EStrongs File Explorer 即: Es文件浏览器 网络 -> 远程管理器 设置 ->设置根目录 linux 使用浏览器访问即可.

  8. 第4次oo作业

    作业概述 作业1:多项式加法 第一次作业理解上并不困难,简言之是一个多项式合并同类项,但对于我这个第一次使用java进行编程的小白,还是充满了血和泪. 在这次课程之前,我稍微对java有一些了解,但也 ...

  9. c++入门之运算符重载

    c++函数重载:可以将一个函数名用于不同功能的函数.从而处理不同的对象.对于运算符,同样也有这样的用途,即对同一个标志符的运算符,可以运用到不同的功能中去. 首先引入:运算符重载,在C语言中甚至都有运 ...

  10. c++学习之字符串拼接

    在这里,强调这样一个问题: 可以看出,c++中,定义了string类,string 类方便我们进行字符串的一些操作,而不是像C语言中采用字符数组的方式或者指针的方式,通过上面的一些描述,可以发现: s ...