网络高级(学习)2024.9.10
目录
一、Modbus简介
1.起源
2.特点
3.应用场景
二、Modbus TCP协议
1.特点
2.协议格式
3.MBAP报文头
4.功能码
5.寄存器
(1)线圈寄存器,类比为开关量,每一个bit都对应一个信号的开关状态。
(2)离散输入寄存器,离散输入寄存器就相当于线圈寄存器的只读模式,每个bit表示一个开关量,而开关量只能读取输入的开关信号,不能写的。
(3)保持寄存器,这个寄存器的单位不再是bit而是两个byte,也就是可以存放具体的数据量的,并且是可读写的。
(4)输入寄存器,这个和保持寄存器类似,但是也是只支持读而不能写。
三、工具软件
1.modbus软件
Modbus slave端
Modbus poll端
2.wireshark软件
过滤器选择
过滤条件
3.网络调试助手
四、代码编程
1.读取保持寄存器中的数值(功能号03),起始地址40001,寄存器个数1个
2.编程实现主机功能,写入单个线圈状态(功能号05)
一、Modbus简介
1.起源
Modbus由Modicon公司于1979年开发,是一种工业现场总线协议标准。
Modbus通信协议具有多个变种,其中有支持串口,以太网多个版本,其中最著名的是Modbus RTU、Modbus ASCII、Modbus TCP三种
2.特点
免费、简单、容易使用
3.应用场景
Modbus协议是现在国内工业领域应用最多的协议,不只PLC设备,各种终端设备,比如水控机、水表、电表、工业秤、各种采集设备。
二、Modbus TCP协议
1.特点
(1)Modbus TCP采用主从问答方式(master/slave)通信,有一个节点是master节点,其他使用Modbus协议参与通信的节点是slave节点(可以多个),每一个slave设备都有一个唯一的地址
(2)Modbus TCP是基于TCP实现的应用层协议
(3)默认端口号为502
2.协议格式

3.MBAP报文头
Modbus TCP协议包含一个7字节报文头
事务处理标识符:2字节,报文的序列号
协议标识符:2字节,0000表示Modbus TCP协议
长度:2字节,字节长度
单元标识符:1字节,从机地址
4.功能码
根据四种不同的寄存器设置了8种功能码,根据实际需要设置不同的功能码
在协议中,功能码占1个字节
| 功能码 | 作用 | 寄存器PLC地址 | 位操作/字操作 | 操作数量 |
| 01 | 读线圈状态 | 00001-09999 | 位操作 | 单个或多个 |
| 02 | 读离散输入状态 | 10001-19999 | 位操作 | 单个或多个 |
| 03 | 读保持寄存器 | 40001-49999 | 字操作 | 单个或多个 |
| 04 | 读输入寄存器 | 30001-39999 | 字操作 | 单个或多个 |
| 05 | 写单个线圈 | 00001-09999 | 位操作 | 单个 |
| 06 | 写单个保持寄存器 | 40001-49999 | 字操作 | 单个 |
| 15 | 写多个线圈 | 00001-09999 | 位操作 | 多个 |
| 16 | 写多个保持寄存器 | 40001-49999 | 字操作 | 多个 |
5.寄存器
Modbus TCP通过寄存器的方式存储数据。
一共有四种类型的寄存器,分别是:离散量输入、线圈、输入寄存器、保持寄存器。
离散量和线圈其实就是位寄存器(每个寄存器数据占1个字节),工业上主要用于控制IO设备。输入和保持寄存器是字寄存器(每个寄存器数据占2个字节),工业上主要用于存储工业设备的值。
(1)线圈寄存器,类比为开关量,每一个bit都对应一个信号的开关状态。
所以一个byte就可以同时控制8路的信号。比如控制外部8路io的高低。 线圈寄存器支持读也支持写,写在功能码里面又分为写单个线圈寄存器和写多个线圈寄存器。
功能码:0x01 0x05 0x0f
(2)离散输入寄存器,离散输入寄存器就相当于线圈寄存器的只读模式,每个bit表示一个开关量,而开关量只能读取输入的开关信号,不能写的。
比如读取外部按键是按下还是松开。
功能码:0x02
(3)保持寄存器,这个寄存器的单位不再是bit而是两个byte,也就是可以存放具体的数据量的,并且是可读写的。
比如设置时间年月日,不但可以写也可以读出来现在的时间。写也分为单个写和多个写
功能码:0x03 0x06 0x10
(4)输入寄存器,这个和保持寄存器类似,但是也是只支持读而不能写。
一个寄存器也是占据两个byte的空间。类比我我通过读取输入寄存器获取现在的AD采集值
功能码:0x04
三、工具软件
1.modbus软件
Modbus slave端
此端是从机,相当于服务器,需要先运行
设置:setup->设置从机ID、指定寄存器、起始地址、个数
连接:connection->connect,设置ip和端口号,进行连接
Modbus poll端
此端是主机,相当于客户端
设置:setup->设置从机ID、功能码、起始地址、个数
连接:connection->connect,设置ip和端口号,进行连接
2.wireshark软件
过滤器选择
如果是在windows下本地测试选择Loopback adapter
如果数据经过路由器,选择WLAN
过滤条件
过滤ip:ip.addr == ip地址
过滤端口号:tcp.port == 端口号
过滤协议类型:协议类型名
注:每个条件通过&&连接,最后敲回车生效
3.网络调试助手

四、代码编程
1.读取保持寄存器中的数值(功能号03),起始地址40001,寄存器个数1个
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("sockfd 失败");return -1;}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(502);saddr.sin_addr.s_addr = inet_addr("192.168.50.121");socklen_t addrlen = sizeof(saddr);if (connect(sockfd, (struct sockaddr *)&saddr, addrlen) < 0){perror("connect失败\n");return -1;}printf("connect 成功\n");#define N 32uint8_t buf[N] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, 0x01};uint8_t buf1[N];unsigned int n;send(sockfd, buf, N, 0);sleep(1);int ret = recv(sockfd, buf1, N, 0);if (ret < 0){perror("recv失败");return -1;}else if (ret == 0){printf("连接关闭\n");return 0;}else{for (int i = 0; i < ret; i++){printf("0x%X ", buf1[i]);}printf("\n");}close(sockfd);return 0;
}
封装成函数:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>#define N 32int sockfd;void read_hold_register(int socket, uint8_t addr, uint8_t fun, uint16_t addra, uint16_t count)
{uint8_t buf[N] = {0};buf[0] = 0x00; // 事务处理标识符(高位)buf[1] = 0x00; // 事务处理标识符(低位)buf[2] = 0x00; // 协议标识符(高位)buf[3] = 0x00; // 协议标识符(低位)buf[4] = 0x00;buf[5] = 0x06; // 字节长度buf[6] = addr; // 从机地址buf[7] = fun; // 功能码buf[8] = addra >> 8; // 寄存器起始地址(高位)buf[9] = addra & 0x00ff; // 寄存器起始地址(低位)buf[10] = count >> 8; // 寄存器数量(高位)buf[11] = count & 0x00ff; // 寄存器数量(低位)send(socket, buf, N, 0); // 发送请求memset(buf, 0, N); // 清空缓冲区int ret = recv(socket, buf, N, 0); // 接收响应if (ret < 0){perror("recv失败");return;}else if (ret == 0){printf("连接关闭\n");return;}else{for (int i = 0; i < ret; i++){printf("0x%X ", buf[i]);}printf("\n");}
}int main(int argc, char const *argv[])
{sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket 失败");return -1;}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(502);saddr.sin_addr.s_addr = inet_addr("192.168.50.121");socklen_t addrlen = sizeof(saddr);if (connect(sockfd, (struct sockaddr *)&saddr, addrlen) < 0){perror("connect 失败");close(sockfd);return -1;}printf("connect 成功\n");uint8_t fun, addr;uint16_t addra, count;printf("请输入功能码(格式0x01):");scanf(" %hhx", &fun);printf("请输入从机地址(格式0x01):");scanf(" %hhx", &addr);printf("请输入起始地址(格式0x0001):");scanf(" %hx", &addra);printf("请输入寄存器数量(格式0x0001):");scanf(" %hx", &count);read_hold_register(sockfd, addr, fun, addra, count);close(sockfd);return 0;
}
2.编程实现主机功能,写入单个线圈状态(功能号05)
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("sockfd 失败");return -1;}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(502);saddr.sin_addr.s_addr = inet_addr("192.168.50.121");socklen_t addrlen = sizeof(saddr);if (connect(sockfd, (struct sockaddr *)&saddr, addrlen) < 0){perror("connect失败\n");return -1;}printf("connect 成功\n");#define N 32uint8_t buf[N] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00};uint8_t buf1[N];unsigned int n;send(sockfd, buf, N, 0);sleep(1);int ret = recv(sockfd, buf1, N, 0);if (ret < 0){perror("recv失败");return -1;}else if (ret == 0){printf("连接关闭\n");return 0;}else{for (int i = 0; i < ret; i++){printf("0x%X ", buf1[i]);}printf("\n");}close(sockfd);return 0;
}
封装成函数:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>#define N 32int sockfd;void read_hold_register(int socket, uint8_t addr, uint8_t fun, uint16_t addra, uint16_t count)
{uint8_t buf[N] = {0};buf[0] = 0x00; // 事务处理标识符(高位)buf[1] = 0x00; // 事务处理标识符(低位)buf[2] = 0x00; // 协议标识符(高位)buf[3] = 0x00; // 协议标识符(低位)buf[4] = 0x00;buf[5] = 0x06; // 字节长度buf[6] = addr; // 从机地址buf[7] = fun; // 功能码buf[8] = addra >> 8; // 线圈地址(高位)buf[9] = addra & 0x00ff; // 线圈地址(低位)buf[10] = count >> 8; // 断通标志(高位)buf[11] = count & 0x00ff; // 断通标志(低位)send(socket, buf, 12, 0); // 发送请求memset(buf, 0, N); // 清空缓冲区int ret = recv(socket, buf, N, 0); // 接收响应if (ret < 0){perror("recv失败");return;}else if (ret == 0){printf("连接关闭\n");return;}else{for (int i = 0; i < ret; i++){printf("0x%X ", buf[i]);}printf("\n");}
}int main(int argc, char const *argv[])
{sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket 失败");return -1;}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(502);saddr.sin_addr.s_addr = inet_addr("192.168.50.121");socklen_t addrlen = sizeof(saddr);if (connect(sockfd, (struct sockaddr *)&saddr, addrlen) < 0){perror("connect 失败");close(sockfd);return -1;}printf("connect 成功\n");uint8_t fun, addr;uint16_t addra, count;printf("请输入功能码(格式0x01):");scanf(" %hhx", &fun);printf("请输入从机地址(格式0x01):");scanf(" %hhx", &addr);printf("请输入线圈地址(格式0x0001):");scanf(" %hx", &addra);printf("请输入断通标志(格式0x0001):");scanf(" %hx", &count);read_hold_register(sockfd, addr, fun, addra, count);close(sockfd);return 0;
}
相关文章:
网络高级(学习)2024.9.10
目录 一、Modbus简介 1.起源 2.特点 3.应用场景 二、Modbus TCP协议 1.特点 2.协议格式 3.MBAP报文头 4.功能码 5.寄存器 (1)线圈寄存器,类比为开关量,每一个bit都对应一个信号的开关状态。 (2)…...
【软件全文档】项目概要设计说明书(2024实际项目Word原件)
一、 引言 (一) 编写目的 (二) 范围 (三) 文档约定 (四) 术语 二、 项目概要 (一) 建设背景 (二) 建设目标 (三࿰…...
震惊!国产数据库厂商减少了51家!
前面文章我提到国产数据库厂商实际上大部分都不赚钱,我估计国产目前国产数据库厂商利润为正的,目前不超过5家。 而经济寒冬,融资困难,那么对于很多厂商,尤其是全靠融资的数据库厂商来讲,这将变得极其困难。…...
[AI书籍分享]<AI时代,学什么,怎么学 - 和渊>
本文由Markdown语法编辑器编辑完成。 1, 背景: 本书是一位清华大学毕业的生物学博士,和渊老师,现就职于人大附中, 是一名一线的高中生物教师. 她之前已经写过几本关于教育类的书籍,而这本书,则是她针对当前, AI时代迅猛发展的背…...
鸿蒙HarmonyOS开发:一次开发,多端部署(界面级)断点和媒体查询
文章目录 概述引入与使用流程媒体查询条件语法规则媒体类型(media-type)媒体逻辑操作(media-logic-operations)媒体特征(media-feature) 场景示例1、监听设备屏幕的方向(竖屏,横屏&a…...
1 Linux SSH安全加固_linux system-auth
 RabbitMQ详解
RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用。 消息中间件最主要的作用是解耦,中间件最标准的用法是生产者生产消息传送到队列,消费者从队列中拿取消息并处理&…...
《华为 eNSP 模拟器安装教程》
1.电脑安装环境要求: 检查电脑是否安装过 eNSP 和依赖软件,如果有,请全部卸载。 安装软件列表: 2.软件安装: 安装 WinPcap: 打开安装包,单击【Next】 单击【I Agree】 单击【Install】 单击【…...
vector(二)vector模拟实现
vector成员变量是三个迭代器 vector的迭代器底层与string相同是使用 指针实现的 使用的是类模版T*指针 template<class T> class vector { public:typedef T* iterator;typedef const T* const_iterator; private:iterator _start nullptr;iterator _finish nullp…...
【Canvas与电脑桌面】用六角回旋镖铺满一个平面(1920*1080)
【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>六角回旋镖桌面1920x1080</title><style type"text/cs…...
创游系列开心娱乐完整组件
别人分享的一套东西,是个不错的娱乐源码,里面包含了很多小游戏。可以创建房间。 没测试自行研究吧,内含搭建教程。 代码免费下载:百度网盘...
高效驱动之选 ——KP85211ASGA 半桥栅极驱动器 内置互锁死区
KP85211A是一款 225V 耐压,具有 1A 拉电流和 1.5A 灌电流能力的半桥栅极驱动器,专用于驱动功率MOSFET或IGBT。采用高压器件工艺技术,具有良好的电流输出及出色的抗瞬态干扰能力。可保证开关节点 VS 瞬态 -7V 情况下系统正常工作。可支持开关节…...
建投数据获批安全生产许可证
9月1日,建投数据成功获批由北京市住房和城乡建设委员会核发的《安全生产许可证》。该资质的获得,是建投数据能力与实力的展现,更是对其企业规模、管理水平、项目业绩等的肯定。 《安全生产许可证》是国家为了加强安全生产监督管理,…...
MCU9.reg52.h的介绍
1.引用头文件的两种方式 #include <reg52.h> #include "reg52.h" 区别:优先搜索的位置不同! 在keil软件中 #include <reg52.h> 优先搜索软件安装的INC文件夹 #include "reg52.h" 优先搜索当前工程文件夹下的头文件,如果没有,则在软件安装的…...
Python知识点:如何使用Python进行二维码生成与识别
在Python中,生成和识别二维码可以使用不同的库来实现。最常用的库包括 qrcode 和 pyzbar。以下是如何使用这些库来生成和识别二维码的示例: 1. 生成二维码 你可以使用 qrcode 库来生成二维码。首先,你需要安装它: pip install …...
跨域问题(CORS)
文章目录 介绍解决一、添加跨域头,允许跨域1.后端配置CORS策略(4种方法)2.配置nginx 二、代理 介绍 跨域资源共享(CORS, Cross-Origin Resource Sharing)是浏览器的一个安全机制,用来防止来自一个域的网页对另一个域下的资源进行…...
评测AI写毕业论文软件排行榜前十名的网站
在当今信息爆炸的时代,AI智能写作工具已经成为我们写作过程中的得力助手。特别是对于学术论文的撰写,这些工具不仅能够提高写作效率,还能帮助用户生成高质量的文稿。以下是五款值得推荐的AI智能写论文软件,其中特别推荐千笔-AIPas…...
发邮件格式
邮件作为一种正式的沟通方式,其格式通常需要遵循一定的规范。 尊敬的xx:(无缩进) 您好!(缩进两个字符) 正文(缩进两个字符)xxx正文xxx正文xxx正文xxx正文xxx正文xxx正文xxx正文xxx正文xxx正文xxx正文xxx正文xxx正文xxx正文xxx正文xx…...
解锁Web3.0——Scaffold-eth打造以太坊DApp的终极指南
🚀本系列文章为个人学习笔记,目的是巩固知识并记录我的学习过程及理解。文笔和排版可能拙劣,望见谅。 目录 前言 一、快速部署 1、前期准备: 2、安装项目: 二、配置部署运行环境 1、初始化本地链:…...
机器学习之监督学习(四)决策树和随机森林
机器学习之监督学习(四)决策树和随机森林 0. 文章传送1. 决策树 Decision Tree案例引入构建过程 2. 随机森林 Random Forest3. 决策树 vs 神经网络4. 代码实现手写版本sklearn版本 5. 案例Iris数据集介绍实验代码 0. 文章传送 机器学习之监督学习&#…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
Python环境安装与虚拟环境配置详解
本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南,适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者,都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...
FTXUI::Dom 模块
DOM 模块定义了分层的 FTXUI::Element 树,可用于构建复杂的终端界面,支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...
