Modbus TCP

Modbus

(👆 百度百科,放心跳转)

起源

Modbus 由 Modicon 公司于 1979 年开发,是一种工业现场总线协议标准。

Modbus 通信协议具有多个变种,支持串口,以太网 多个版本,其中最著名的是 Modbus RTU、

Modbus ASCII 和 Modbus TCP 三种。Modbus TCP 是在施耐德收购 Modicon 后 1997 年发布的。

分类

1、Modbus RTU (Remote Terminal Unit)

运行在串口上的协议,采用二进制表现形式以及紧凑的数据结构,通信效率高,应用广泛。

2、Modbus ASCII

运行在串口上的协议,采用 ASCII 码进行传输,并且在每个字节的开始和结束 都有特殊字符作为标志,传输效率远远低于 Modbus RTU,只有传输数据量较小时,才会考虑。

3、Modbus TCP

运行在以太网上的协议。

优势

免费、简单、容易使用。

应用场景

Modbus 协议是现在国内工业领域应用最多的协议,不只 PLC 设备,各种终端设备,比如水控机、水表、电表、工业秤、各种采集设备,都应用此协议。

通信

1、Modbus 采用主从问答式(master / slave)通信;

有一个节点是 master 节点,其他使用 Modbus 协议参与通信的节点是 slave 节点(可多个), 每个 slave 设备都有唯一一个地址。

Modbus TCP

Modbus TCP 协议 和 Modbus RTU 协议非常相似,只要把 RTU 协议中两个字节的校验码去掉,然后在 RTU 协议的开始加上 5 个 0 和 1 个 6,通信时通过 TCP/IP 网络协议发送出去即可。

特点

1、见"Modbus ------> 通信";

2、该协议是 应用层的协议,基于传输层的 TCP协议 进行通信;
3、Modbus TCP 默认接收报文的端口号为 502。

协议格式(报文头 + 功能码 + 数据)

Modbus TCP/IP 协议 最大数据帧长度为 260 字节。报文格式如下:

报文头

功能码

寄存器

线圈寄存器 ,类比为开关量,每一个 bit 都对应一个信号的开关状态,所以 一个 byte 就可以同时控制8 路的信号 。 线圈寄存器支持 也支持写,写又分为写单个 线圈寄存器和写多个 线圈寄存器。

对应功能码:0x01 0x05 0x0f
离散输入寄存器 ,相当于线圈寄存器的只读模式,也是每个 bit 表示一个开关量,其开关量只能读取输入的开关信号,是不能写的。比如 取外部按键的按下还是松开。

对应功能码: 0x02
保持寄存器 ,单位不再是 bit 而是两个 byte,是可以存放具体的数据量的。比如设置时间年月日,不但可以写入也可以读出 。该寄存器并可读写的,写也分为写单个 保持寄存器和写多个 保持寄存器。

对应功能码: 0x03 0x06 0x10
输入寄存器 ,和保持寄存器类似,但也只支持读而不能写。一个寄存器也是占据两个 byte 的空间。比如,通过读取 输入寄存器获取现在的 AD 采集值。

对应功能码: 0x04

读数据

主机 ------>从机

报文头 + 功能码 + 起始地址 + 数量

7 + 1 + 2 + 2 = 12
从机 ------>主机

报文头 + 功能码 + 字节计数 + 数据

7 + 1 + 1 + n = 9 + n

0x01(读线圈状态)
0x02(读离散输入状态)
0x03(读保持寄存器)
0x04(读输入寄存器)

写单个

主机 ------>从机

报文头 + 功能码 + 地址 + 断通标志 / 数据

7 + 1 + 2 + 2 = 12
从机 ------>主机

原文返回

0x05(写单个线圈)
0x06(写单个保持寄存器)

写多个

主机 ------>从机

报文头 + 功能码 + 起始地址 + 数量 + 字节计数 + 数据

7 + 1 + 2 + 2 + 1 + n = 13 + n
从机 ------>主机

报文头 + 功能码 + 起始地址 + 数量

7 + 1 + 2 + 2 = 12

0x0F(写多个线圈)
0x10(写多个保持寄存器)

工具软件的安装与使用

Modbus poll

破解

点击 connection -> connect,输入序列号即可。

使用

先设置,后连接。

Modbus slave

破解

点击 connection -> connect,输入序列号即可。

使用

先设置,后连接。

网络调试助手



Wireshark(Windows 版)

捕获器选择:
复制代码
如果连接有线网络,选择本地连接 / 以太网;
如果连接无线网络,选择 WLAN;
如果只是在本机上的通信,可以选择 NPCAP Loopback apdater 
						   或 Adapter for loopback traffic capture。
过滤条件:

1、过滤端口:tcp.port == 502

2、过滤IP:ip.addr == Windows 的IP



练习:

1、读传感器数据,读1个寄存器数据,写出主从数据收发协议。

2、写出控制 IO 设备开关的协议数据,操作1个线圈,置1。

3、在虚拟机编写客户端,实现 poll 端功能,和 Slave 通信,读保持寄存器的三个值。

c 复制代码
    uint8_t hldreg[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 
        												0x00, 0x00, 0x00, 0x03};
    send(sockfd, hldreg, sizeof(hldreg), 0);

    uint8_t buf[32] = {};
    recv(sockfd, buf, sizeof(buf), 0);
    
    for (int i = 0; i < buf[8]; i++)
        printf("%#x ", buf[9+i]);
    putchar(10);

运行结果如下:

4、编写客户端程序,实现对 Slave 单个线圈的控制(置一)。

c 复制代码
    uint8_t coil[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x05, 
        												0x00, 0x00, 0xff, 0x00};
    send(sockfd, coil, sizeof(coil), 0);

运行结果如下:

5、封装函数:设置单元标识符(从机地址)

c 复制代码
void set_slave_id(uint8_t *p, int slave_id){
    p[6] = slave_id;
}

6、封装函数:读保持寄存器

c 复制代码
void read_hldreg(int addr, int num, uint8_t *hldreg, uint8_t *dest){
   
   hldreg[5] = 0x06;
   hldreg[7] = 0x03;
   hldreg[8] = addr >> 8;
   hldreg[9] = addr & 0xff;
   hldreg[10] = num >> 8;
   hldreg[11] = num & 0xff;

   send(sockfd, hldreg, 12, 0);			// 指针类型,不能 sizeof(hldreg)
   recv(sockfd, dest, 64, 0);				// 64 为数组 dest 的长度,sockfd 为全局变量
}
相关推荐
hrrrrb5 分钟前
【TCP/IP】12. 文件传输协议
服务器·网络·tcp/ip
网安小白的进阶之路3 小时前
A模块 系统与网络安全 第四门课 弹性交换网络-2
网络·安全·web安全·系统安全·交换机
安全系统学习3 小时前
网络安全之RCE分析与利用详情
服务器·网络·安全·web安全·系统安全
武汉唯众智创3 小时前
网络安全实训室建设方案全攻略
网络·安全·web安全·网络安全·网络安全实训室·网络安全实验室
啟明起鸣4 小时前
【网络编程】简易的 p2p 模型,实现两台虚拟机之间的简单点对点通信,并以小见大观察 TCP 协议的具体运行
c语言·网络·tcp/ip·p2p
追烽少年x4 小时前
设计模式---观察者模式(发布-订阅模式)
网络·设计模式
宝山哥哥6 小时前
网络信息安全学习笔记1----------网络信息安全概述
网络·笔记·学习·安全·网络安全
专注VB编程开发20年6 小时前
常见 HTTP 方法的成功状态码200,204,202,201
开发语言·网络协议·tcp/ip·http
Dsocc7 小时前
TCP 动态选路协议全面研究:OSPF、BGP 与 IS-IS 的比较与应用分析
网络·网络协议·tcp/ip
YC运维7 小时前
RIP实验以及核心原理
运维·网络·智能路由器