ModbusTCP通信协议分析
前言
大家好!我是付工。前面给大家介绍了一系列关于RS485与Modbus的知识。
今天跟大家聊聊关于ModbusTCP协议的那些事。
一、发展历史
ModbusTCP是一种基于以太网的通信协议.ModbusTCP协议由施耐德公司在1996年推出,它继承了ModbusRTU协议的核心功能,但主要通过TCP/IP以太网进行数据传输,实现了设备之间的主从式通信。
在实际应用中,针对串口ModbusRTU,我们通过采用主站/从站的说明双方的角色,对于ModbusTCP,我们通过使用服务器/客户端来定义双方的角色。
二、通用格式
学习通信协议,首先要弄清楚通用报文格式。我们首先来分析一下ModbusTCP与ModbusRTU的区别:
我们可以看出,ModbusTCP在Modbus串行通信的基础上,去除了差错校验和附加地址(即从站地址),然后加上MBAP报文头(7 Bytes)。
1. ModbusTCP协议一般用 于TCP或UDP通信,而TCP和UDP本身就具备数据校验,因此不需要再加校验了。
2、ModbusTCP主要用于以太网通信,因此,不再需要通过附加地址(即从站地址) 来区分不同的设备,因为以太网设备一般会使用IP地址来区分。
因此,我们只需要了解MBAP报文头即可,因为功能码和数据部分与ModbusRTU协议是一样的,下面主要针对MBAP报文头进行分析说明。
域 | 长度 | 描述 | 客户机 | 服务器 |
事务处理标识符 | 2字节 | Modbus请求/响应的识别码 | 客户机启动 | 复位响应 |
协议标识符 | 2字节 | 0=Modbus协议 | 客户机启动 | 复位响应 |
长度 | 2字节 | 后续字节的数量 | 客户机启动 | 服务器启动 |
单元标识符 | 1字节 | 串行链路或其它总线上连接的远程从站的识别码 | 客户机启动 | 复位响应 |
【1】事务处理标识符:事务处理标识符可以理解为报文的编号,服务器会复制客户端 的事务处理标识符进行响应,因此事务处理标识符并没有实际意义,一般情况下我们会使用ID自增的方式,事务处理标识符占用2个字节长度。
【2】协议标识符:协议标识符设计时是为了区分不同的协议,但是在实际应用中,只有一个协议Modbus协议,用0来表示,协议标识符占用2个字节长度,所以协议标识符是固定值0x00 0x00。
【3】长度:长度表示它后面有多少个字节,即单元标识符、功能码、数据这三个部分 的字节个数,长度占用2个字节长度。
【4】单元标识符:单元标识符与从站地址是相似的,因为ModbusTCP去除了从站地址, 所以在MBAP报文头中加入单元标识符,防止有些场合需要通过一个标识来区别不同的子设备,比如一个串口服务器下挂了多个串口设备,那么就需要单元标识符来区别不同的串口设备,实际应用中单元标识符的值由服务器决定。
综合来看,ModbusTCP协议的通用报文格式如下所示:
事务处理标识符 | 协议标识符 | 长度 | 单元标识符 | 功能码 | 数据 |
2 bytes | 2 bytes | 2 bytes | 1 byte | 1 byte | N bytes |
下面针对常用的几个功能码进行详细讲解。
三、读取输出线圈
读取输出线圈发送报文格式如下:
我们来分析一下这段发送报文:
【1】事务/协议:事务处理标识符和协议标识符都是用的固定值0x00 0x00。
【2】长度:单元标识符、功能码、数据部分总共是6个字节,因此长度是0x00 0x06。
【3】单元标识符:单元标识符默认是0x01。
【4】功能码:0x01表示读取的是输出线圈存储区。
【5】起始地址:十六进制0x00 0x13对应十进制为19,表示从19号线圈开始读取,这个 19对应的Modbus地址为00020。
【6】线圈数量:十六进制 0x00 0x1B对应十进制的27,表示读取线圈数量为27。
这段发送报文表示的含义是客户端想要读取服务器输出线圈存储区,Modbus地址从 00020-00046,共27个线圈的状态值。
当服务器收到这段报文后,响应报文如下:
我们再来分析一下这段响应报文:
【1】事务/协议:事务标识符服务器是复制发送报文的,是固定值0x00 0x00。
【2】长度:单元标识符、功能码、数据部分总共是7个字节,因此长度是0x00 0x07。
【3】单元标识符:单元标识符与发送报文一致。
【4】功能码:0x01表示这帧报文响应的是0x01功能码的报文。
【5】字节计数:0x04表示返回的数据总共有4个字节。
【6】字节1至字节4:返回的具体数据分别为0xCD、0x6B、0xB2、0x05,这4个字节对 应32个线圈值,前面的27个线圈值即对应00020-00046的值。
客户端收到响应报文便获取到了自己要的数据,具体对应关系如下: 0xCD=1100 1101 对应 00027-00020 0x6B=0110 1011 对应 00035-00028 0xB2=1011 0010 对应 00043-00036 0x05=0000 0101 对应 00051-00044至此,就完成了一次Modbus通信交互。
至于读取输入线圈,与读取输出线圈几乎一致,唯一的区别就是功能码从0x01变成了0x02,这里就不做过多赘述了。
四、读取保持型寄存器
读取保持型寄存器发送报文格式如下:
这个与读取输出线圈是相似的,只不过这里的起始地址是寄存器地址。
我们来分析一下这段发送报文:
【1】事务/协议:事务处理标识符和协议标识符都是用的固定值0x00 0x00。
【2】长度:单元标识符、功能码、数据部分总共是6个字节,因此长度是0x00 0x06。
【3】单元标识符:单元标识符默认是0x01。
【4】功能码:0x03表示读取的是保持型寄存器存储区。
【5】起始地址:十六进制0x00 0x6B对应十进制为107,表示从107号寄存器开始读取, 这个107对应的Modbus地址为40108。
【6】寄存器数量:0x00 0x02对应十进制的2,表示读取寄存器数量为2。
客户端发送这段报文是想要读取服务器保持型寄存器存储区,Modbus地址 从40108-40109,共2个寄存器的数据值。
服务器响应报文格式如下:
我们再来分析一下这段响应报文:
【1】事务/协议:事务标识符服务器是复制发送报文的,是固定值0x00 0x00。
【2】长度:单元标识符、功能码、数据部分总共是7个字节,因此长度是0x00 0x07。
【3】单元标识符:单元标识符与发送报文一致。
【4】功能码:0x03表示这帧报文响应的是0x03功能码的报文。
【5】字节计数:0x04表示返回的数据总共有4个字节。
【6】字节1至字节4:返回的具体数据分别为0x00、0xC8、0x01、0x2C,这4个字节对 应2个保持型寄存器的值,即对应40108-40109的值。
客户端收到响应报文便获取到了自己要的数据,具体对应关系如下:
0x00 0xC8对应40108的值,16进制的0x00 0xC8对应十进制的200
0x01 0x2C对应40109的值,16进制的0x01 0x2C对应十进制的300
读取输入寄存器,与读取保持型寄存器报文格式几乎一致,唯一的区别就是功能码从0x03变成了0x04,这里就不做过多赘述了。
五、预置单线圈
我们对0x05功能码预置单线圈进行说明,发送报文格式如下:
我们来分析一下这段发送报文:
【1】事务/协议:事务处理标识符和协议标识符都是用的固定值0x00 0x00。
【2】长度:单元标识符、功能码、数据部分总共是6个字节,因此长度是0x00 0x06。
【3】单元标识符:单元标识符默认是0x01。
【4】功能码:0x05表示写入单个输出线圈。
【5】线圈地址:十六进制0x00 0x1A对应十进制为26,表示写入26号线圈,这个26对 应的Modbus地址为00027。
【6】断通标志:0xFF 0x00表示置位,就是将该线圈状态设置为True。这段发送报文表示的含义是客户端想要将服务器输出线圈存储区,Modbus地址00027这个线圈置为True。
接收报文格式如下:
预置单线圈接收报文与发送报文一致,原报文返回。
六、预置单寄存器
我们对0x06功能码预置单寄存器进行说明,发送报文格式如下:
我们来分析一下这段发送报文:【1】事务/协议:事务处理标识符和协议标识符都是用的固定值0x00 0x00。 【2】长度:单元标识符、功能码、数据部分总共是6个字节,因此长度是0x00 0x06。 【3】单元标识符:单元标识符默认是0x01。 【4】功能码:0x06表示写入单个保持型寄存器。 【5】寄存器地址:十六进制0x00 0x10对应十进制为16,表示写入16号寄存器,这个16 对应的Modbus地址为40017。 【6】写入值:16进制0x03 0x00对应十进制768,就是将该寄存器的值设置为768。这段发送报文表示的含义是主站想要将1号从站保持型寄存器存储区,Modbus地址 40017这个寄存器的值修改为768。接收报文格式如下:
预置单寄存器接收报文与发送报文一致,原报文返回。
七、预置多线圈
0x0F功能码预置多线圈发送报文格式如下:
我们来分析一下这段发送报文:
【1】事务/协议:事务处理标识符和协议标识符都是用的固定值0x00 0x00。
【2】长度:单元标识符、功能码、数据部分总共是6个字节,因此长度是0x00 0x06。
【3】单元标识符:单元标识符默认是0x01。
【4】功能码:0x0F表示写入多个输出线圈。
【5】起始地址:十六进制0x00 0x13对应十进制为19,表示从19号线圈开始写入,这个 19对应的Modbus地址为00020。
【6】数量:十六进制0x00 0x0A对应十进制为10,表示连续写入10个线圈,Modbus地 址从00020到00029。
【7】写入值:0x0F 0x03表示写入的两个字节,第一个字节对应前8个线圈,第二个字节 对应后面的线圈。这段发送报文表示客户端想要对服务器输出线圈存储区,从Modbus地址 00020开始的10个线圈值进行修改,0x0F对应二进制00001111,对应前8个线圈,就是将00020-00027写入11110000,0x03对应二进制00000011,对应后面的线圈,也就是将00028-00029写入11。
接收报文格式如下:
预置多输出线圈接收报文是在发送报文基础上除去字节数及写入值。
八、预置多寄存器
0x10功能码预置多寄存器发送报文格式如下:
我们来分析一下这段发送报文:
【1】事务/协议:事务处理标识符和协议标识符都是用的固定值0x00 0x00。
【2】长度:单元标识符、功能码、数据部分总共是6个字节,因此长度是0x00 0x06。
【3】单元标识符:单元标识符默认是0x01。
【4】功能码:0x10表示写入多个保持型寄存器。
【5】起始地址:十六进制0x00 0x10对应十进制为16,表示从16号寄存器开始写入,这 个16对应的Modbus地址为40017。
【6】数量:十六进制0x00 0x02对应十进制为2,表示连续写入2个寄存器,Modbus地 址从40017到40018。
【7】字节数:0x04表示4个字节,因为1个寄存器对应2个字节,2个寄存器对应4个字节。
【8】写入值:0x01 0x0A 0x01 0x10表示写入的4个字节,前2个字节对应第1个寄存器, 后二个字节对应第二个寄存器。这段发送报文表示的含义是客户端想要对服务器1号从站保持型存储区,从Modbus地址40017 开始的2个寄存器值进行修改,0x01 0x0A对应十进制266,对应第1个寄存器,也就是 将40017写入266,0x01 0x10对应十进制272,对应第2个寄存器,也就是将40018写入272。
接收报文格式如下:
预置多寄存器接收报文是在发送报文基础上除去字节数及写入值。
ModbusTCP通信协议分析的更多相关文章
- 史上最全的njRAT通信协议分析
Njrat,又称Bladabindi,该木马家族使用.NET框架编写,是一个典型的RAT类程序,通过控制端可以操作受控端的文件.进程.服务.注册表内容,也可以盗取受控端的浏览器的保存的密码信息等内容. ...
- 网络抓包及Http Https通信协议分析
Wireshark基本介绍和学习TCP三次握手 之前写过一篇博客:用 Fiddler 来调试HTTP,HTTPS. 这篇文章介绍另一个好用的抓包工具wireshark, 用来获取网络数据封包,包括ht ...
- (原创)MODBUS-TCP协议分析
- IM通信协议逆向分析、Wireshark自定义数据包格式解析插件编程学习
相关学习资料 http://hi.baidu.com/hucyuansheng/item/bf2bfddefd1ee70ad68ed04d http://en.wikipedia.org/wiki/I ...
- u-boot分析(八)----串口初始化
u-boot分析(八) 上篇博文我们按照210的启动流程,分析到了内存初始化,今天我们继续按照u-boot的启动流程对串口的初始化进行分析. 今天我们会用到的文档: 1. 2440芯片手 ...
- IoTClient开发3 - ModBusTcp协议客户端实现
前言 进过前面两章的介绍,今天开始正式的实战. 进制转换 很多朋友对于进制转换可能是在刚学计算机的时候有接触,后来做高级语言开发可能就慢慢忘记了.我们做工控开发的时候需要经常进行进制转换,这里和大家一 ...
- IoTClient开发4 - ModBusTcp协议服务端模拟
前言 上篇我们实现了ModBusTcp协议的客户端读写,可是在很多时候编写业务代码之前是没有现场环境的.总不能在客户现场去写代码,或是蒙着眼睛写然后求神拜佛不出错,又或是在办公室部署一套硬件环境.怎么 ...
- 【新阁教育】基于ModbusTCP实现西门子1200PLC定位控制案例
1. 引言 今天新阁教育给大家分享一个<基于ModbusTCP实现西门子1200PLC定位控制案例>,从PLC输入输出及步进电机接线开始,到PLC运动控制程序编写,再到后续的ModbusT ...
- MySQL 通讯协议
Client/Server 通讯协议用于客户端链接.代理.主备复制等,支持 SSL.压缩,在链接阶段进行认证,在执行命令时可以支持 Prepared Statements 以及 Stored Proc ...
- 如何阅读 Redis 源码?ZZ
原文链接 在这篇文章中, 我将向大家介绍一种我认为比较合理的 Redis 源码阅读顺序, 希望可以给对 Redis 有兴趣并打算阅读 Redis 源码的朋友带来一点帮助. 第 1 步:阅读数据结构实现 ...
随机推荐
- vue项目中实现sql编辑器功能自定义高亮词汇可提示关键词-codemirror
先上图:左侧是数据库表,右侧上部是sql编辑器,下部是执行sql的返回接口 HTML: <el-row> <el-col :span="4" class=&quo ...
- mysql索引失效的情况七字口诀:“模型数空运最快”
mysql索引失效的情况 七字口诀:"模型数空运最快" 模:使用like进行模糊查询的时候,以百分号%开头的,索引就会失效. 型:代表数据类型,数据类型错误了,索引也会失效. 数: ...
- windows环境xampp搭建php电商项目/搭建禅道
windows环境xampp搭建php论坛/电商项目 一,首先下载xampp https://www.apachefriends.org/zh_cn/index.html 下载之后解压到E盘或者F盘的 ...
- 【MySQL】 将字段相同的记录排在一起,按时间倒序
一.实现效果: 蓝牙mac字段是相同的记录,排在一起,再按时间倒序,总体时间来说也需要倒序 二.SQL编写: 最开始的想法就是,那我直接按mac和时间排序不就好了 SELECT * FROM aca_ ...
- 【SpringBoot】Re 02 Import与自定义装配实现
Import的注册形式: 1.使用@Import导入一个或者多个类字节对象 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME ...
- 【Mybatis-Plus】06 代码生成器 CodeGenerator
导入生成器需要的依赖坐标: <dependency> <groupId>com.baomidou</groupId> <artifactId>mybat ...
- (续)在深度计算框架MindSpore中如何对不持续的计算进行处理——对数据集进行一定epoch数量的训练后,进行其他工作处理,再返回来接着进行一定epoch数量的训练——单步计算
内容接前文: https://www.cnblogs.com/devilmaycry812839668/p/14988686.html 这里我们考虑的数据集是自建数据集,那么效果又会如何呢??? im ...
- 《最新出炉》系列初窥篇-Python+Playwright自动化测试-64 - Canvas和SVG元素推拽
1.简介 今天宏哥分享的在实际测试工作中很少遇到,比较生僻,如果突然遇到我们可能会脑大.懵逼,一时之间不知道怎么办?所以宏哥这里提供一种思路供大家学习和参考. 2.SVG简介 svg也是html5新增 ...
- list 中的Stream 累加操作
ublic class Test { public static void main(String[] args) { double sum = 860.10 + 1808.09; double su ...
- 旧物利用 - 将机顶盒改造为一台Linux开发机!
前言 机顶盒型号:移动魔百盒CM201-2(CH),芯片组: hi3798mv300(hi3798mv3dmm),其他型号类似 理论上适用于以下SOC:Hi3798Mv100 / Hi3798Cv20 ...