Qt下使用ModbusTcp通信协议进行PLC线圈/保持寄存器的读写(32位有符号数)
文章目录
- 前言
- 一、引入Modbus模块
- 二、Modbus设备的连接
- 三、各寄存器数据的读取
- 四、各寄存器数据的写入
- 五、示例完整代码
- 总结
前言
本文主要讲述了使用Qt的Modbus模块来进行ModbusTcp的通信,实现对PLC的线圈寄存器和保持寄存器的读写,基于TCP/IP的Modbus协议的内容我就不做过多解释了,详见参考文章。在本文示例中采用QModbusTcpClient类作为Modbus客户端(主站),PLC作为从站,封装了一个自己的MyModbus类,希望可以帮助到大家,如有错误之处,欢迎大家批评指正。
项目效果

提示:以下是本篇文章正文内容,下面案例可供参考
一、引入Modbus模块
1.这里我实现了自己的MyModbus类的封装,使用了pri子模块的方式,也是方便日后进行此模块的复用
pri中引入Modbus模块:
MyModbus.pri
QT += serialbus serialport
MyModbus类中添加相关头文件
#include <QModbusTcpClient>
#include <QModbusDataUnit>
二、Modbus设备的连接
1.ModbusTcp的连接只需要配置好连接参数IP+Port
//判断当前连接状态是否为断开状态
if(myClient->state() != QModbusDevice::ConnectedState)
{//配置ModbusTcp的连接参数IP+PortmyClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter,ip);myClient->setConnectionParameter(QModbusDevice::NetworkPortParameter,port);myClient->connectDevice();
}
三、各寄存器数据的读取
1.Modbus中有4种操作对象,这4种都能进行读取操作:线圈、离散输入、保持寄存器、输入寄存器
//读取modbus设备各寄存器数据
//typeNum:1_线圈 2_离散输入 3_保持 4_输入
bool MyModbus::readModbusData(int typeNum,int startAdd,quint16 numbers)
{if(myClient->state() != QModbusDevice::ConnectedState){return false;}//确定寄存器类型QModbusDataUnit ReadUnit;if(typeNum == 1){ReadUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,numbers);}else if(typeNum == 2){ReadUnit = QModbusDataUnit(QModbusDataUnit::DiscreteInputs,startAdd,numbers);}else if(typeNum == 3){ReadUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,numbers);}else if(typeNum == 4){ReadUnit = QModbusDataUnit(QModbusDataUnit::InputRegisters,startAdd,numbers);}else{LOGDEBUG<<"读取寄存器类型错误";return false;}LOGDEBUG<<"readModbusData typeNum:"<<typeNum;//多读if(auto *reply = myClient->sendReadRequest(ReadUnit,1)){if(!reply->isFinished()){if((typeNum == 1) || (typeNum == 2)){QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyCoils); //读取线圈}if((typeNum == 3) || (typeNum == 4)){QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyRegisters); //读取寄存器}//reply->deleteLater();return true;}else{reply->deleteLater();return false;}}else{LOGDEBUG<<"读取错误:" + myClient->errorString();return false;}
}
四、各寄存器数据的写入
1.Modbus中4种操作对象只有这2种能进行写入操作:线圈 、保持寄存器
//对modbus设备各寄存器写入数据
//typeNum:1_线圈 2_保持 (这两类寄存器可读可写,其余的只读)
bool MyModbus::writeModbusData(int typeNum,int startAdd,int writeNum)
{if(myClient->state() != QModbusDevice::ConnectedState){return false;}//确定寄存器类型QModbusDataUnit writeUnit;if(typeNum == 1){writeUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,1); //写入一个数据writeUnit.setValue(0,writeNum);//单写//bool ok;//quint16 hexData = writeData.toInt(&ok,16); //转16进制}else if(typeNum == 2){writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,2); //写入两个数据quint16 uData16[2] = {0};uData16[0] = writeNum & 0xffff;uData16[1] = (writeNum >> 16) & 0xffff;writeUnit.setValue(0,uData16[0]);writeUnit.setValue(1,uData16[1]);//LOGDEBUG<<"uData16[0]:"<<uData16[0]<<" uData16[1]:"<<uData16[1]<<" writeNum:"<<writeNum;}else{LOGDEBUG<<"写入寄存器类型错误";return false;}//LOGDEBUG<<"writeModbusData typeNum:"<<typeNum<<" writeNum:"<<writeNum;if(auto *reply = myClient->sendWriteRequest(writeUnit,1)){if(!reply->isFinished()){connect(reply,&QModbusReply::finished,this,[reply](){if(reply->error() == QModbusDevice::NoError){reply->deleteLater();return true;}else{LOGDEBUG<<"写入返回错误:"<<reply->error();reply->deleteLater();return false;}});}else{reply->deleteLater();return false;}}else{LOGDEBUG<<"写入错误:" + myClient->errorString();return false;}return true;
}
五、示例完整代码
这里是示例项目的完整代码,包含pro主程序和MyModbus.pri子文件
1.ModbusTest.pro
QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11#定义编译选项.QT_DEPRECATED_WARNINGS表示当Qt的某些功能被标记为过时的,那么编译器会发出警告.
DEFINES += QT_DEPRECATED_WARNINGS#设置字符(MSCV编译器下防止中文乱码)
contains( CONFIG,"msvc" ):QMAKE_CXXFLAGS += /source-charset:utf-8 /execution-charset:utf-8
contains( CONFIG,"msvc" ):QMAKE_CFLAGS +=/source-charset:utf-8 /execution-charset:utf-8include (./MyModbus/MyModbus.pri)SOURCES += \main.cpp \widget.cppHEADERS += \widget.hFORMS += \widget.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
2.MyModbus.pri
QT += serialbus serialportHEADERS += \$$PWD/mymodbus.hSOURCES += \$$PWD/mymodbus.cpp
3.mymodbus.h
#ifndef MYMODBUS_H
#define MYMODBUS_H#include <QObject>
#include <QModbusTcpClient>
#include <QModbusDataUnit>
#include <QDebug>#define LOGDEBUG qDebug()<<__FILE__<<__LINE__class MyModbus : public QObject
{Q_OBJECT
public:explicit MyModbus(QObject *parent = nullptr);~MyModbus();void initModbus();void connectToModbus(QString ip,int port);bool readModbusData(int typeNum,int startAdd,quint16 numbers);bool writeModbusData(int typeNum,int startAdd,int writeNum);signals:void signal_stateChanged(bool flag);void signal_readCoils(QVector<quint16> vAllData);void signal_readRegisters(int resultNum);private slots:void slot_stateChanged();void slot_readReadyCoils();void slot_readReadyRegisters();private:QModbusTcpClient *myClient;};
#endif // MYMODBUS_H
4.mymodbus.cpp
#include "mymodbus.h"MyModbus::MyModbus(QObject *parent) : QObject(parent)
{this->initModbus();
}MyModbus::~MyModbus()
{}//初始化
void MyModbus::initModbus()
{myClient = new QModbusTcpClient();//connect(myClient,SIGNAL(stateChanged()),this,SLOT(slot_stateChanged()));connect(myClient,&QModbusClient::stateChanged,this,&MyModbus::slot_stateChanged);
}//连接到modbus设备
void MyModbus::connectToModbus(QString ip,int port)
{if(!myClient){return;}//判断当前连接状态是否为断开状态if(myClient->state() != QModbusDevice::ConnectedState){//配置ModbusTcp的连接参数IP+PortmyClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter,ip);myClient->setConnectionParameter(QModbusDevice::NetworkPortParameter,port);myClient->connectDevice();}//else//{// myClient->disconnectDevice();//}
}//读取modbus设备各寄存器数据
//typeNum:1_线圈 2_离散输入 3_保持 4_输入
bool MyModbus::readModbusData(int typeNum,int startAdd,quint16 numbers)
{if(myClient->state() != QModbusDevice::ConnectedState){return false;}//确定寄存器类型QModbusDataUnit ReadUnit;if(typeNum == 1){ReadUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,numbers);}else if(typeNum == 2){ReadUnit = QModbusDataUnit(QModbusDataUnit::DiscreteInputs,startAdd,numbers);}else if(typeNum == 3){ReadUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,numbers);}else if(typeNum == 4){ReadUnit = QModbusDataUnit(QModbusDataUnit::InputRegisters,startAdd,numbers);}else{LOGDEBUG<<"读取寄存器类型错误";return false;}LOGDEBUG<<"readModbusData typeNum:"<<typeNum;//多读if(auto *reply = myClient->sendReadRequest(ReadUnit,1)){if(!reply->isFinished()){if((typeNum == 1) || (typeNum == 2)){QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyCoils); //读取线圈}if((typeNum == 3) || (typeNum == 4)){QObject::connect(reply,&QModbusReply::finished,this,&MyModbus::slot_readReadyRegisters); //读取寄存器}//reply->deleteLater();return true;}else{reply->deleteLater();return false;}}else{LOGDEBUG<<"读取错误:" + myClient->errorString();return false;}
}//对modbus设备各寄存器写入数据
//typeNum:1_线圈 2_保持 (这两类寄存器可读可写,其余的只读)
bool MyModbus::writeModbusData(int typeNum,int startAdd,int writeNum)
{if(myClient->state() != QModbusDevice::ConnectedState){return false;}//确定寄存器类型QModbusDataUnit writeUnit;if(typeNum == 1){writeUnit = QModbusDataUnit(QModbusDataUnit::Coils,startAdd,1); //写入一个数据writeUnit.setValue(0,writeNum);//单写//bool ok;//quint16 hexData = writeData.toInt(&ok,16); //转16进制}else if(typeNum == 2){writeUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters,startAdd,2); //写入两个数据quint16 uData16[2] = {0};uData16[0] = writeNum & 0xffff;uData16[1] = (writeNum >> 16) & 0xffff;writeUnit.setValue(0,uData16[0]);writeUnit.setValue(1,uData16[1]);//LOGDEBUG<<"uData16[0]:"<<uData16[0]<<" uData16[1]:"<<uData16[1]<<" writeNum:"<<writeNum;}else{LOGDEBUG<<"写入寄存器类型错误";return false;}//LOGDEBUG<<"writeModbusData typeNum:"<<typeNum<<" writeNum:"<<writeNum;if(auto *reply = myClient->sendWriteRequest(writeUnit,1)){if(!reply->isFinished()){connect(reply,&QModbusReply::finished,this,[reply](){if(reply->error() == QModbusDevice::NoError){reply->deleteLater();return true;}else{LOGDEBUG<<"写入返回错误:"<<reply->error();reply->deleteLater();return false;}});}else{reply->deleteLater();return false;}}else{LOGDEBUG<<"写入错误:" + myClient->errorString();return false;}return true;
}//监听TCP连接的状态,若状态发生改变,发出对应的信号
void MyModbus::slot_stateChanged()
{LOGDEBUG<<myClient->state();if(myClient->state() == QModbusDevice::ConnectedState){emit signal_stateChanged(true);}else if(myClient->state() == QModbusDevice::UnconnectedState){emit signal_stateChanged(false);}
}//接收到读取线圈/离散输入寄存器请求后执行的槽函数
void MyModbus::slot_readReadyCoils()
{QVector<quint16> vAllData;QModbusReply *reply = qobject_cast<QModbusReply *>(sender());if(!reply){LOGDEBUG<<"读取线圈/离散输入寄存器错误";return;}if(reply->error() == QModbusDevice::NoError){const QModbusDataUnit unit = reply->result();vAllData = unit.values();emit signal_readCoils(vAllData);}else{LOGDEBUG<<"线圈/离散输入寄存器回复错误:"<<reply->error();}reply->deleteLater();
}//接收到读取保持/输入寄存器请求后执行的槽函数
void MyModbus::slot_readReadyRegisters()
{QModbusReply *reply = qobject_cast<QModbusReply *>(sender());if(!reply){LOGDEBUG<<"读取保持/输入寄存器错误";return;}if(reply->error() == QModbusDevice::NoError){const QModbusDataUnit unit = reply->result();auto valueList = unit.values();int nSize = valueList.size();if(nSize == 2){quint16 uData16[2] = {0};uData16[0] = valueList[0];uData16[1] = valueList[1];int resultNum = uData16[0] | (uData16[1] << 16);//LOGDEBUG<<"uData16[0]:"<<uData16[0]<<" uData16[1]:"<<uData16[1]<<" resultNum:"<<resultNum;emit signal_readRegisters(resultNum);}else{LOGDEBUG<<"保持寄存器返回数据错误,个数:"<<nSize;}}else{LOGDEBUG<<"保持/输入寄存器回复错误:"<<reply->error();}reply->deleteLater();
}/*
//读取保持/输入寄存器数据的另一种方式,已废弃
//当前数据格式为大端模式,高位存低地址
//判断正负数,以高8位的16进制是否为f判断
int resultNum = 0;
if(QString::number(valueList[1],16).left(1) == "f") //负数
{//判断是否小于-65535,高16位的10进制为65535if(valueList[1] == 65535){resultNum = valueList[0] - 65536;}else{resultNum = (valueList[1] - 65535) * 65536 + (valueList[0] - 65536);}
}
else
{//判断是否大于65535,高16位的10进制大于0if(valueList[1] > 0){resultNum = valueList[1] * 65536 + valueList[0];}else{resultNum = valueList[0];}
}
*/
5.widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QFileDialog>
#include <QDateTime>
#include <QMessageBox>
#include "MyModbus/mymodbus.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void initWidget();private slots:void slot_stateChanged(bool flag);void slot_readCoils(QVector<quint16> vAllData);void slot_readRegisters(int resultNum);private slots:void on_pb_connect_clicked();void on_pb_readM_clicked();void on_pb_writeM_clicked();void on_pb_readD_clicked();void on_pb_writeD_clicked();private:Ui::Widget *ui;MyModbus *m_myModsbus; //MyModbus对象};
#endif // WIDGET_H
6.widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->initWidget();
}Widget::~Widget()
{delete ui;
}void Widget::initWidget()
{//初始化MyModbus对象m_myModsbus = new MyModbus();connect(m_myModsbus,SIGNAL(signal_stateChanged(bool)),this,SLOT(slot_stateChanged(bool)));connect(m_myModsbus,SIGNAL(signal_readCoils(QVector<quint16>)),this,SLOT(slot_readCoils(QVector<quint16>)));connect(m_myModsbus,SIGNAL(signal_readRegisters(int)),this,SLOT(slot_readRegisters(int)));}void Widget::slot_stateChanged(bool flag)
{if(flag){ui->lb_state->setText("连接成功");ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "连接成功");QMessageBox::warning(this,"警告","连接成功!");}else{ui->lb_state->setText("连接断开");ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "连接断开");QMessageBox::warning(this,"警告","连接断开!");}
}void Widget::slot_readCoils(QVector<quint16> vAllData)
{LOGDEBUG<<"readCoils size:"<<vAllData.size();for(int i=0;i<vAllData.size();i++){LOGDEBUG<<"i:"<<vAllData[i];ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "读取M区返回数据:" + QString::number(vAllData[i]));ui->le_dataM->setText(QString::number(vAllData[0]));}
}void Widget::slot_readRegisters(int resultNum)
{LOGDEBUG<<"resultNum:"<<resultNum;ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "读取D区返回数据:" + QString::number(resultNum));ui->le_dataD->setText(QString::number(resultNum));
}void Widget::on_pb_connect_clicked()
{QString ip = ui->le_ip->text();int port = ui->le_port->text().toInt();LOGDEBUG<<"ip:"<<ip<<" port:"<<port;ui->te_show->appendPlainText(QTime::currentTime().toString("hh:mm:ss: ") + "ip:" + ip + " port:" + QString::number(port));//连接到modbus设备m_myModsbus->connectToModbus(ip,port);
}void Widget::on_pb_readM_clicked()
{int startAdd = ui->le_addressM->text().toInt();LOGDEBUG<<"startAdd:"<<startAdd;if(!m_myModsbus->readModbusData(1,startAdd,1)){QMessageBox::warning(this,"警告","M区数据读取失败!");}
}void Widget::on_pb_writeM_clicked()
{int startAdd = ui->le_addressM->text().toInt();int writeNum = ui->le_dataM->text().toInt();LOGDEBUG<<"startAdd:"<<startAdd<<" writeNum:"<<writeNum;//单写if(!m_myModsbus->writeModbusData(1,startAdd,writeNum)){QMessageBox::warning(this,"警告","M区数据写入失败!");}
}void Widget::on_pb_readD_clicked()
{int startAdd = ui->le_addressD->text().toInt();LOGDEBUG<<"startAdd:"<<startAdd;if(!m_myModsbus->readModbusData(3,startAdd,2)){QMessageBox::warning(this,"警告","D区数据读取失败!");}
}void Widget::on_pb_writeD_clicked()
{int startAdd = ui->le_addressD->text().toInt();int writeNum = ui->le_dataD->text().toInt();;LOGDEBUG<<"startAdd:"<<startAdd<<" writeNum:"<<writeNum;//进行写入寄存器数据的处理if(!m_myModsbus->writeModbusData(2,startAdd,writeNum)){QMessageBox::warning(this,"警告","D区数据写入失败!");}
}
7.main.cpp
#include "widget.h"
#include <QApplication>
#include <QMutex>//程序输出日志
void outputMessage(QtMsgType type,const QMessageLogContext &context,const QString &msg)
{static QMutex mutex;mutex.lock();//初始化log文件夹QString logFilePath = QCoreApplication::applicationDirPath() + "/LogFile/";QDir dstDir(logFilePath);if(!dstDir.exists()){if(!dstDir.mkpath(logFilePath)){LOGDEBUG<<"程序输出日志创建失败!";}else{LOGDEBUG<<"程序输出日志创建成功!";}}//获取输出内容QString debugMsg;if(type == QtDebugMsg){QString debugDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");debugMsg = QString("%1\n%2%3").arg(debugDateTime).arg(msg).arg(context.function);}//保存文件QString curDate = QDate::currentDate().toString("yyyyMMdd");QString logFile = logFilePath + "log_" + curDate + ".txt";QFile file(logFile);file.open(QIODevice::WriteOnly | QIODevice::Append);QTextStream textStream(&file);textStream << debugMsg << "\n\n";file.flush();file.close();mutex.unlock();
}int main(int argc, char *argv[])
{QApplication a(argc, argv);qInstallMessageHandler(outputMessage);Widget w;w.show();return a.exec();
}
8.widget.ui

总结
基于Qt使用这个ModbusTcp协议进行通信,还是比较简单的,首先就是确定下寄存器的类型,直接使用相关的函数进行读写。需要注意的一点是在进行保持寄存器读写的时候,我们PLC某个地址上的数是个16位的数,所以在进行32位有符号数读写的时候,要考虑两个相邻地址的组合,文中就对此进行了处理,这种情况下PLC那边也别忘记进行相应的设置哈。
hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。
参考博客:
QT下的Modbus TCP 通讯
C++与PLC通过Modbus TCP协议进行PLC内部寄存器的值的读取/写入总结
相关文章:
Qt下使用ModbusTcp通信协议进行PLC线圈/保持寄存器的读写(32位有符号数)
文章目录 前言一、引入Modbus模块二、Modbus设备的连接三、各寄存器数据的读取四、各寄存器数据的写入五、示例完整代码总结 前言 本文主要讲述了使用Qt的Modbus模块来进行ModbusTcp的通信,实现对PLC的线圈寄存器和保持寄存器的读写,基于TCP/IP的Modbus…...
ElasticSearch学习2
1、索引的操作 1、创建索引 对ES的操作其实就是发送一个restful请求,kibana中在DevTools中进行ES操作 创建索引时需要注意ES的版本,不同版本的ES创建索引的语句略有差别,会导致失败 如下创建一个名为people的索引,settings&…...
3D角色展示
先看效果: 再看代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>3D卡片悬停</title><style>font-face {font-family: "Exoct";src: url("htt…...
前端面试:【Angular】打造强大Web应用的全栈框架
嗨,亲爱的Angular探险家!在前端开发的旅程中,有一个全栈框架,那就是Angular。Angular提供了模块化、组件化、依赖注入、路由和RxJS等特性,助力你构建强大、可扩展的Web应用。 1. 什么是Angular? Angular是…...
数据结构:栈和队列
文章目录 一、栈1.栈的概念及结构1.栈的概念及结构2.栈的实现 2.栈的顺序表实现1.栈的结构体和实现的功能函数2.栈的初始化,入栈和出栈操作3.栈的其他操作 3.栈的链表实现1.栈的结构体和实现的功能函数2.栈功能函数的实现 二、队列1.队列的概念及结构1.队列的概念及…...
SpringCloud Gateway服务网关的介绍与使用
目录 1、网关介绍2、SpringCloudGateway工作原理3、三大组件3.1 、Route(路由)3.2、断言 Predicate3.3、过滤器 filter 4、Gateway整合nacos的使用4.1 、引入依赖4.2、 编写基础类和启动类4.3、 编写基础配置和路由规则4.4 、测试结果 1、网关介绍 客户…...
深入解析:如何打造高效的直播视频美颜SDK
在当今数字化时代,视频直播已经成为人们交流、娱乐和信息传递的重要方式。然而,许多人在直播时都希望能够呈现出最佳的外观,这就需要高效的直播视频美颜技术。本文将深入解析如何打造高效的直播视频美颜SDK,以实现令人满意的视觉效…...
每日一博 - MPP(Massively Parallel Processing,大规模并行处理)架构
文章目录 概述优点缺点小结 概述 MPP(Massively Parallel Processing,大规模并行处理)架构是一种常见的数据库系统架构,主要用于提高数据处理性能。它通过将多个单机数据库节点组成一个集群,实现数据的并行处理。 在 …...
ssh框架原理及流程
1.hibernate工作原理: 读取并解析配置文件读取并解析映射信息,创建sessionFactory打开session创建事务transaction持久化操作提交事务关闭session关闭sessionFactory 为什么使用: 对JDBC访问数据库的代码做了封装,大大简化了数据…...
eslint 配置和用法
在一个使用Webpack的项目中配置ESLint,你可以按照以下步骤操作: 首先,你需要在你的项目中安装ESLint和对应的Webpack loader。你可以使用npm或者yarn来安装。在你的项目根目录下打开终端,然后运行以下命令: 使用npm&…...
字符设备驱动实例(PWM和RTC)
目录 五、PWM 六、RTC 五、PWM PWM(Pulse Width Modulation,脉宽调制器),顾名思义就是一个输出脉冲宽度可以调整的硬件器件,其实它不仅脉冲宽度可调,频率也可以调整。它的核心部件是一个硬件定时器,其工作原理可以用…...
Ribbon 源码分析
Ribbon 源码分析 Ribbon Debug 分析 断点 LoadBalancerInterceptor LoadBalancerInterceptor 实现了 ClientHttpRequestInterceptor 接口,重写了其中的 intercept 方法,用来拦截请求; 获取原始的 uri 和 服务名,调用 LoadBalanc…...
【1-3章】Spark编程基础(Python版)
课程资源:(林子雨)Spark编程基础(Python版)_哔哩哔哩_bilibili 第1章 大数据技术概述(8节) 第三次信息化浪潮:以物联网、云计算、大数据为标志 (一)大数据 大数据时代到来的原因…...
宇宙原理:黑洞基础。
宇宙原理:黑洞基础TOC 黑洞的数理基础:一个由满数组成的数盘,经过自然演进,将会逐步稀疏化、最终会向纯数方案发展;纯数方案虽然只有{2}、无数(虚拟)、{0,1,2,3}(虚拟)、…...
分类预测 | MATLAB实现SCNGO-CNN-LSTM-Attention数据分类预测
分类预测 | MATLAB实现SCNGO-CNN-LSTM-Attention数据分类预测 目录 分类预测 | MATLAB实现SCNGO-CNN-LSTM-Attention数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.SCNGO-CNN-LSTM-Attention数据分类预测程序,改进算法,融合正余弦和…...
Android学习之路(7) Frament
Fragment 表示应用界面中可重复使用的一部分。fragment 定义和管理自己的布局,具有自己的生命周期,并且可以处理自己的输入事件。fragment 不能独立存在。它们必须由 activity 或其他 fragment 托管。fragment 的视图层次结构会成为宿主的视图层次结构的…...
metallb , istio ingress 部署httpbin使用例子
安装metaillb,参考:Kubernetes的负载均衡方案:MetalLB - 文章详情 wget https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-frr.yaml -O metallb.yaml kubectl apply -f metallb-frr.yaml 配置负载均衡ip池 apiVe…...
基于swing的销售管理系统java仓库库存信息jsp源代码mysql
本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 基于swing的销售管理系统 系统有1权限:管…...
FreeCAD傻瓜式教程之约束设定和构建实体、开孔、调整颜色等
本内容基于官方教程中的绘制简单的零件中的体会,在初次绘制的时候,总是无法完成,几经尝试才发现其关键点所在,以此文记录,用以被查资料,同时也希望能够帮到纯白新手快速熟悉该软件的绘图方法。 一、. 打开…...
代码随想录算法训练营day41 | 343. 整数拆分,96. 不同的二叉搜索树
目录 343. 整数拆分 96. 不同的二叉搜索树 343. 整数拆分 类型:动态规划 难度:medium 思路: dp[i]所用的拆分方法至少已经拆分了两次,比如dp[2]1,小于2,在大于2的数中,最后的2是不会拆的。 …...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
