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是不会拆的。 …...
飞天使-k8sv1.14二进制安装
文章目录 安装前准备安装前设置分发脚本 开始安装k8s集群cfssl 安装部署kubectl命令行工具创建admin证书和私钥创建kubeconfig文件部署ETCD集群部署Flannel网络kube-apiserver 高可用KeepLived 部署部署master节点部署高可用kube-controller-manager集群kube-controller-manage…...
TypeScript封装Axios
TypeScript封装Axios Axios的基本使用 因axios基础使用十分简单,可参考axios官方文档,这里不在介绍他基本用法,主要讲解拦截器。 拦截器主要分为两种,请求拦截器和响应拦截器。 请求拦截器:请求发送之前进行拦截&…...
指针(一)【C语言进阶版】
大家好,我是深鱼~ 【前言】: 指针的主题,在初阶指针章节已经接触过了,我们知道了指针的概念: 1.指针就是个变量,用来存放地址,地址的唯一标识一块内存空间(指针变量)&a…...
回归预测 | MATLAB实现SA-BP模拟退火算法优化BP神经网络多输入单输出回归预测(多指标,多图)
回归预测 | MATLAB实现SA-BP模拟退火算法优化BP神经网络多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现SA-BP模拟退火算法优化BP神经网络多输入单输出回归预测(多指标,多图)效果一览基本介…...
springMVC 已解密的登录请求
问题描述: 解决方案: 1.对用户所输入的密码在页面进行MD5加密并反馈至密码输入框。 2. 手动生成SSL安全访问证书;在此不做介绍,相关方法可通过网上查找; 3. 将产品HTTP访问方式改为SSL安全访问方式;在Ap…...
机器学习赋能乳腺癌预测:如何使用贝叶斯分级进行精确诊断?
一、引言 乳腺癌是女性最常见的恶性肿瘤之一,也会发生在男性身上。每年全球有数百万人被诊断出乳腺癌,对患者的生活和健康造成了巨大的影响。早期的乳腺癌检测和准确的诊断对于提高治疗的成功率至关重要。然而,乳腺癌的早期诊断面临着许多挑战…...
Java后端开发面试题——框架篇
Spring框架中的bean是单例的吗?Spring框架中的单例bean是线程安全的吗? singleton : bean在每个Spring IOC容器中只有一个实例。 prototype:一个bean的定义可以有多个实例。 Spring bean并没有可变的状态(比如Service类和DAO类),…...
【新版】系统架构设计师 - 系统测试与维护
个人总结,仅供参考,欢迎加好友一起讨论 文章目录 架构 - 系统测试与维护考点摘要软件测试软件测试 - 测试类型软件测试 - 静态测试软件测试 - 动态测试软件测试 - 测试阶段软件测试 - 测试阶段 - 单元测试软件测试 - 测试阶段 - 集成测试软件测试 - 测试…...
使用 useEffect 和 reactStrictMode:优化 React 组件的性能和可靠性
使用useEffect和React.StrictMode是一种优化React组件性能和可靠性的常见做法。下面是关于如何使用这两个特性的示例: import React, { useEffect } from react;function MyComponent() {useEffect(() > {// 在组件挂载/更新时执行的副作用代码// 可以进行数据获…...
商业智能BI是什么都不明白,如何实现数字化?
2021年下半年中国商业智能软件市场规模为4.8亿美元,2021年度市场规模达到7.8亿美元,同比增长34.9%,呈现飞速增长的趋势。数字化时代,商业智能BI对于企业的落地应用有着巨大价值,逐渐成为了现代企业信息化、数字化转型中…...
网站建设哪些好/南京seo排名优化公司
文章目录1.1 大数据时代为什么全球数据量 增长如此之快?何谓大数据?1.2 云计算——大数据的计算1.2.1 大数据与云计算的关系1.2.2 云计算长定义1.2.3 云计算短定义1.2.4 云计算的7个特点1.2.5 云计算三类服务类型 (重点)1.3 云计算…...
万网主机服务/徐州seo代理计费
文章目录快速排序1.排序规则2.代码实现3.测试结果4.复杂度分析快速排序 1.排序规则 划分的规则: 第一次排序以第一个数据作为基数 从右向左找比基准值小的(相等) 从左向右找比基准值大的 向下划分:至少这个组里有两个数据&#…...
旧宫网站建设/搜索引擎谷歌入口
本文的学习内容参考:http://blog.csdn.net/yunyun1886358/article/details/5659851 http://blog.csdn.net/xudongdong99/article/details/6723163 1.使用二维数组作为形参的例子: void func(int arr[][10]) { } int main() {int array[10][10]; fu…...
网站开发的业务风险/简述网站建设的基本流程
当数据库进程占CPU为99%,请慎重选择shutdown昨日,发现数据库在没有任何工作的情况下占用CPU为99%,于是选择进行shutdown immediate操作,但无法关闭数据库,再连数据库也连不上了。所以只好重起机器。发出#sh…...
北京华夏网站建设设计公司/文案代写收费标准
学习php创建图像基本方法: // 创建一张200*200的图, 图像指针 $image imagecreate(200, 200);// 填充白色背景 imagecolorallocate($image, 0xFF, 0xFF, 0xFF); // white background // $background imagecolorallocate($image, 0xFF, 0xFF, 0xFF);// 创建黑色 $blackColor …...
汽车门户网站开发/品牌策划包括哪几个方面
【来信】贺老师,您好,我是江西某高校软件学院的一名在校学生。看了您在csdn上公布的博文和视频,我获益良多。不得不承认,之前的大学时光我是荒废了,立即就要大三了,我主攻的是C方面。因此我悔过自新的想从头…...