当前位置: 首页 > news >正文

物联网实战--入门篇之(十)安卓QT--后端开发

目录

一、项目配置

二、MQTT连接

三、数据解析

四、数据更新

五、数据发送

六、指令下发


一、项目配置

        按常规新建一个Quick空项目后,我们需要对项目内容稍微改造、规划下。

        首先根据我们的需要在.pro文件内添加必要的模块,其中quick就是qml了,core那是核心模块,必须的,network是网络模块,MQTT需要使用网络。

        然后就是为QML文件和图片文件各自建立一个资源文件,这样编译的时候会把这些资源带上,否则的话打包发布的时候你需要把QML文件和图片文件放到指定文件夹内,这在安卓里就不方便了。

        最后就是如何加载前端QML文件的问题了,如下图所示,后端通过QML加载引擎QQmlApplicationEngine把QML主文件加载进来就能显示界面了,下一行是前端到后端的设置接口名称,这样在QML文件里就可以用theMainInterface这个名称引用后端的函数了,完成开关、调速等动作。

        在新工程默认的文件里,加载前端文件这一步是在main.c文件里完成的,我们这里为了整体前后端的交互,特意建了一个MainInterface的类,在主函数中直接定义这个类的变量即可,这样整个工程结构比较清晰。

二、MQTT连接

        QT标准库里没有mqtt,需要自己单独下载GitCode - 开发者的代码家园,我的项目里已经集成了,只要右键添加进来即可,这里主要是要写个自己的MQTT管理类,把状态保活、话题订阅等任务内部处理掉,就是BaseMqtt类了,里面还有个内容是域名解析需要处理。

#include "BaseMqtt.h"BaseMqtt::BaseMqtt(QObject *parent) : QObject(parent)
{isConnected=false;checkTimer = new QTimer(this);checkTimer->setInterval(1*100);//心跳检测checkTimer->start();m_heartTime=0;connect(checkTimer, SIGNAL(timeout()),this,SLOT(slotCheckTimeout()));m_mqttClient=nullptr;m_hostAddress="";
}
BaseMqtt::~BaseMqtt(void)
{qDebug()<<"~BaseMqtt, hostName="<<m_connectParam.hostName;
}void BaseMqtt::slotLookUpHost(QHostInfo info)
{if(info.error() == QHostInfo::NoError){foreach (QHostAddress address, info.addresses()){m_hostAddress=address.toString();qDebug()<<m_connectParam.hostName<<" mqtt found ip= "<<m_hostAddress;break;}}
}void BaseMqtt::slotCheckTimeout(void)
{m_heartTime++;if(m_hostAddress.isEmpty()){if(m_heartTime%10==0){qDebug("mqtt start dns!");QHostInfo::lookupHost(m_connectParam.hostName, this, SLOT(slotLookUpHost(QHostInfo)));}return;}if(m_mqttClient==nullptr){if(!m_connectParam.certPath.isEmpty())//使用SSL连接{QFile file;QByteArray client_key_text, client_crt_text, root_crt_text;QString certPath=m_connectParam.certPath;QSslSocket ssl_socket;file.setFileName(certPath+"/client.key");file.open(QIODevice::ReadOnly | QIODevice::Text);client_key_text = file.readAll();file.close();file.setFileName(certPath+"/client.crt");file.open(QIODevice::ReadOnly | QIODevice::Text);client_crt_text = file.readAll();file.close();file.setFileName(certPath+"/rootCA.crt");file.open(QIODevice::ReadOnly | QIODevice::Text);root_crt_text = file.readAll();file.close();QSslKey client_key(client_key_text, QSsl::Rsa);QSslCertificate client_crt(client_crt_text);            ssl_socket.setPrivateKey(client_key);ssl_socket.setLocalCertificate(client_crt);QSslConfiguration ssl_config=QSslConfiguration::defaultConfiguration();ssl_config.setCaCertificates(QSslCertificate::fromData(root_crt_text)); //QSslCertificate::fromPath(certPath+"/rootCA.crt"); ssl_config.setPrivateKey(ssl_socket.privateKey());ssl_config.setLocalCertificate(ssl_socket.localCertificate());ssl_config.setPeerVerifyMode(QSslSocket::QueryPeer);ssl_config.setPeerVerifyDepth(10);ssl_config.setProtocol(QSsl::TlsV1_2);m_mqttClient = new QMQTT::Client(m_hostAddress, m_connectParam.hostPort, ssl_config, true, this);
//            qDebug()<<"\n###SSL PrivateKey="<<ssl_config.privateKey();
//            qDebug()<<"###SSL Certificate="<<ssl_config.localCertificate();
//            qDebug()<<"###SSL rootCA="<<ssl_config.caCertificates();
//            qDebug()<<"hostName="<<m_hostAddress<<", hostPort="<<m_connectParam.hostPort;
//            qDebug()<<"userName="<<m_connectParam.userName<<", passWord="<<m_connectParam.passWord<<", clientID="<<m_connectParam.clientID;}else//普通连接{QHostAddress host(m_hostAddress);m_mqttClient = new QMQTT::Client(host, m_connectParam.hostPort, this);}signalSlotInit();m_mqttClient->setUsername(m_connectParam.userName);m_mqttClient->setPassword(m_connectParam.passWord);m_mqttClient->setClientId(m_connectParam.clientID);m_mqttClient->setAutoReconnect(true);m_mqttClient->setCleanSession(true);m_mqttClient->setKeepAlive(30);m_mqttClient->connectToHost();}else if(this->mqttIsConnected()){for(auto iter : m_subTopicList)//订阅话题{if(iter.isSubed==false){mqttSubscribeMessage(iter.subTopic, iter.qos);break;}}if(m_heartTime%200==0)//保持连接{
//            qDebug()<<"mqtt send keep";mqttPublishMessage("dev/sub/data1", QByteArray("heart"));}}else{
//        qDebug()<<"BaseMqtt no connected!";}
}void BaseMqtt::mqttConnect(QString hostName, u16 hostPort, QString userName, QByteArray passWord, QString clientID, QString certPath)
{clientID=clientID+QString("_")+takeHostMac().remove(":");m_connectParam.hostName=hostName;m_connectParam.hostPort=hostPort;m_connectParam.userName=userName;m_connectParam.passWord=passWord;m_connectParam.clientID=clientID;m_connectParam.certPath=certPath;u8 *pData=(u8*)hostName.toUtf8().data();if(pData[0]>='0' && pData[0]<='9')//判断是否为域名,使用域名时 域名的第一个字符不能是数字{m_hostAddress=hostName;}
}bool BaseMqtt::mqttIsConnected(void)
{
//    if(m_mqttClient!=nullptr)
//        return m_mqttClient->isConnectedToHost();return isConnected;
}void BaseMqtt::mqttPublishMessage(QString topicFilter, QByteArray msgBa)
{if(m_mqttClient==nullptr || m_mqttClient->isConnectedToHost()==false)return;QMQTT::Message message;message.setTopic(topicFilter);message.setPayload(msgBa);m_mqttClient->publish(message);
}void BaseMqtt::mqttPingresp(void)
{
//    m_mqttClient->pingresp();
}void BaseMqtt::mqttSubscribeMessage(QString topicFilter, quint8 qos)
{if(m_mqttClient==nullptr)return;m_mqttClient->subscribe(topicFilter, qos);
}void BaseMqtt::mqttUnsubscribeMessage(QString topicFilter)
{if(m_mqttClient==nullptr)return;m_mqttClient->unsubscribe(topicFilter);
}void BaseMqtt::signalSlotInit(void)
{connect(m_mqttClient, SIGNAL(connected()), this, SLOT(slotMqttConnected()));connect(m_mqttClient, SIGNAL(disconnected()), this, SLOT(slotMqttDisconnected()));connect(m_mqttClient, SIGNAL(error(QMQTT::ClientError)), this, SLOT(slotMqttError(QMQTT::ClientError)));connect(m_mqttClient, SIGNAL(pingresp()), this, SLOT(slotMqttPingresp()));connect(m_mqttClient, SIGNAL(published(QMQTT::Message,quint16)), this, SLOT(slotMqttPuslished(QMQTT::Message,quint16)));connect(m_mqttClient, SIGNAL(received(QMQTT::Message)), this, SLOT(slotMqttReceived(QMQTT::Message)));connect(m_mqttClient, SIGNAL(subscribed(QString,quint8)), this, SLOT(slotMqttSubscribed(QString,quint8)));connect(m_mqttClient, SIGNAL(unsubscribed(QString)), this, SLOT(slotMqttUnsubscribed(QString)));
}void BaseMqtt::mqttAddTopic(QString topic, u8 qos)
{for(auto iter : m_subTopicList){if(iter.subTopic==topic){qDebug()<<"have the same topic="<<topic;return;}}SubTopicStruct tag_subTopic;tag_subTopic.subTopic=topic;tag_subTopic.isSubed=false;tag_subTopic.qos=qos;m_subTopicList.append(tag_subTopic);qDebug()<<"mqttAddTopic="<<topic;
}void BaseMqtt::mqttDelTopic(QString topic)
{int i=0;for(auto iter : m_subTopicList){if(topic==iter.subTopic){if(iter.isSubed==true){this->mqttUnsubscribeMessage(topic);}m_subTopicList.removeAt(i);qDebug()<<"remove topic="<<topic;return;}i++;}
}void BaseMqtt::slotMqttConnected(void)
{isConnected=true;emit sigMqttConnected();qDebug()<<"clientId="<<m_mqttClient->clientId()<<"connected";
}void BaseMqtt::slotMqttDisconnected(void)
{isConnected=false;int nSize=m_subTopicList.size();for(int i=0; i<nSize; i++){m_subTopicList[i].isSubed=false;}qDebug()<<"clientId="<<m_mqttClient->clientId()<<"disconnected";emit sigMqttDisconnected();
}void BaseMqtt::slotMqttError(const QMQTT::ClientError error)
{qDebug()<<"clientId="<<m_mqttClient->clientId()<<"slotMqttError="<<error;
}void BaseMqtt::slotMqttPingresp(void)
{
//    qDebug("BaseMqtt::slotMqttPingresp");
}void BaseMqtt::slotMqttPuslished(const QMQTT::Message &message, quint16 msgid)
{msgid=message.id();msgid=msgid;
//    qDebug("BaseMqtt::slotMqttPuslished, msgid=%d ", msgid);
//    qDebug()<<"msg="<<message.payload().toHex();
}void BaseMqtt::slotMqttReceived(const QMQTT::Message &message)
{emit sigtMqttReceived(message);}void BaseMqtt::slotMqttSubscribed(const QString &topic, const quint8 qos)
{int i=0;
//    qDebug()<<"slotMqttSubscribed, topic="<<topic<<", qos="<<qos;for(auto iter : m_subTopicList){if(iter.subTopic==topic){m_subTopicList[i].isSubed=true;break;}i++;}emit sigMqttSubscribed(topic, qos);
}void BaseMqtt::slotMqttUnsubscribed(const QString &topic)
{int i=0;for(auto iter : m_subTopicList){if(iter.subTopic==topic){m_subTopicList[i].isSubed=false;break;}i++;}emit sigMqttUnsubscribed(topic);
}QString BaseMqtt::takeHostMac(void)
{DrvCommon drv_com;    return drv_com.takeRandMac();
}

        对于应用层就很简单了,就是创建对象、连接和添加订阅话题即可。其中有个槽函数slotMqttReceived就是用来接收设备发来的数据的。

三、数据解析

        数据解析跟嵌入式端是差不多的,下面是代码,像剥洋葱一样,查找帧头、校验、根据命令类型执行解析。


void MainInterface::slotMqttReceived(const QMQTT::Message &message)
{QByteArray msg_ba=message.payload();u8 *pData=(u8*)msg_ba.data();
//    qDebug()<<"mqtt recv="<<msg_ba.toHex(':');u8 head[2]={0xAA, 0x55};pData=drv_com.memstr(pData, msg_ba.size(), head, 2);if(pData!=nullptr){u16 total_len=pData[2]<<8 | pData[3];u16 crcValue=pData[total_len]<<8 | pData[total_len+1];if(crcValue==drv_com.crc16(pData, total_len)){pData+=4;u32 device_sn=pData[0]<<24|pData[1]<<16|pData[2]<<8|pData[3];pData+=4;m_currDevSn=device_sn;u8 cmd_type=pData[0];pData+=1;qDebug("recv device_sn=%08X, cmd_type=%d", device_sn, cmd_type);m_keepTime=m_secCounts;switch(cmd_type){case AIR_CMD_HEART:{break;}case AIR_CMD_DATA:{int temp=pData[0]<<8|pData[1];//温度 原始数据float temp_f=(temp-1000)/10.f;//温度浮点数据pData+=2;int humi=pData[0]<<8|pData[1];float humi_f=humi/10.f;pData+=2;int pm25=pData[0]<<8|pData[1];pData+=2;u8 speed=pData[0];pData+=1;u8 state=pData[0];pData+=1;qDebug("temp_f=%.1f C, humi_f=%.1f%%, pm25=%d ug/m3, speed=%d, state=%d", temp_f,  humi_f, pm25, speed,state);QString dev_sn_str=QString::asprintf("%08X", device_sn);QString temp_str=QString::asprintf("%.0f", temp_f);QString humi_str=QString::asprintf("%.0f", humi_f);QString pm25_str=QString::asprintf("%03d", pm25);int alarm_level=0;if(pm25<20)alarm_level=0;else if(pm25<30)alarm_level=1;else alarm_level=2;emit siqUpdateSensorValues(dev_sn_str, temp_str, humi_str, pm25_str);emit siqUpdateAlarmLevel(alarm_level);emit siqUpdateSwitchState(state);break;}case AIR_CMD_SET_SPEED:{break;}}}}
}

        这里我们需要把数据送到前端去显示,所以定义了几个信号内容,如下图所示,从上到下依次是状态数据,污染等级和开关状态,这些数据都是设备端发送上来的,通过后端处理加工后发到前端显示。这里对于污染等级的数值可以自定义,我这边为了方便测试是20、30两个分界线,小米的净化器应该是30和80两条线。

 四、数据更新

        对于前端显示,这里先提一下如何接收后端发来的数据的,如下图所示。以Connections对象为基础,设置它的属性target为theMainInterface,这个其实就是我们加载QML文件时候设置的前后端交互名称,这里用上了,相当于是信号发射者;信号接收器就是C++文件里定义的信号函数前面加个on,然后首字母改成大写就可以了,这里是s改为S,这样这里就能接收到后端发送过来的传感器数据了,很简单吧。至于如何显示,放到前端部分再讲解。

五、数据发送

        数据发送底层就是跟嵌入式端一样,组合后通过mqtt发送出去就行了,有点区别就是这时候要带上目标的序列号dev_sn,这样带有序列号的话题设备端才能收到数据。


void MainInterface::airSendLevel(u32 dev_sn, int cmd_type, u8 *cmd_buff, u16 cmd_len)
{u8 make_buff[500]={0};u16 make_len=0;make_buff[make_len++]=0xAA;make_buff[make_len++]=0x55;make_buff[make_len++]=0;make_buff[make_len++]=0;make_buff[make_len++]=dev_sn>>24;make_buff[make_len++]=dev_sn>>16;make_buff[make_len++]=dev_sn>>8;make_buff[make_len++]=dev_sn;make_buff[make_len++]=cmd_type;memcpy(&make_buff[make_len], cmd_buff, cmd_len);make_len+=cmd_len;make_buff[2]=make_len>>8;make_buff[3]=make_len;u16 crcValue=drv_com.crc16(make_buff, make_len);make_buff[make_len++]=crcValue>>8;make_buff[make_len++]=crcValue;QByteArray msg_ba((char*)make_buff, make_len);QString topic=QString::asprintf("air/dev/sub/%08X", dev_sn);if(m_mqttClient){m_mqttClient->mqttPublishMessage(topic, msg_ba);}
}
六、指令下发

        在应用层,主要就是开关和调速两个功能,这里要看下这两个函数的定义,比较特别,在头文件定义的函数名称前多了Q_INVOKABLE,添加了这个关键字后,这个函数就可以在QML文件里直接调用了,是不是很方便。置于函数的内容应该比较简单了,就是组合下报文给底层函数发送出去就行了,这里的命令定义跟嵌入式端是一样的,两边有改动的话一定要及时同步,不然就乱了。对于调速设置,函数的输入是0~1的浮点数,当小于0.1的时候会强制等于0.1,这样调速最低时才不会停掉,只是慢速转动。

        对于这里的后端,总的来说没什么难点,主要还是做好前后端数据交互的准备。这里有个细节提一下,细心的也会发现,有个定时器槽函数slotCheckTimeout(),虽然这里没什么用,但是在其他有复杂任务或者多线程的时候很有用,它可以定时执行任务,相当于局部的main函数了,以后有机会再慢慢学习。

本项目的交流QQ群:701889554

   写于2024-4-2

相关文章:

物联网实战--入门篇之(十)安卓QT--后端开发

目录 一、项目配置 二、MQTT连接 三、数据解析 四、数据更新 五、数据发送 六、指令下发 一、项目配置 按常规新建一个Quick空项目后&#xff0c;我们需要对项目内容稍微改造、规划下。 首先根据我们的需要在.pro文件内添加必要的模块&#xff0c;其中quick就是qml了&…...

[Java]网络编程

网络编程概述 计算机网络&#xff1a; 把分布在不同地理区域的具有独立功能的计算机,通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统。 Java是 Internet 上的语言&#xff0c;它从语言级上提供了对网络应用程序的支持&#xff0c;程序…...

重读Java设计模式: 适配器模式解析

引言 在软件开发中&#xff0c;经常会遇到不同接口之间的兼容性问题。当需要使用一个已有的类&#xff0c;但其接口与我们所需的不兼容时&#xff0c;我们可以通过适配器模式来解决这一问题。适配器模式是一种结构型设计模式&#xff0c;它允许接口不兼容的类之间进行合作。本…...

MySQL面试题系列-9

MySQL是一个关系型数据库管理系统&#xff0c;由瑞典 MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的RDBMS (Relational Database Management System&#xff0c;关系数据…...

书生·浦语训练营二期第二次笔记

文章目录 1. 部署 InternLM2-Chat-1.8B 模型进行智能对话1.1 配置环境1.2 下载 InternLM2-Chat-1.8B 模型 2. 实战&#xff1a;部署实战营优秀作品 八戒-Chat-1.8B 模型2.1 配置基础环境2.2 使用 git 命令来获得仓库内的 Demo 文件&#xff1a;2.3 下载运行 Chat-八戒 Demo 3. …...

python_3

文章目录 题目运行结果模式A模式B模式C模式D 题目 mode input("请选择模式:") n int(input("请输入数字:"))if mode "A" or mode "a":# 模式A n:输入的层数 i:当前的层数# 每行数字循环次数 ifor i in range(1, n 1):for j in r…...

【Python】 使用Apache Tika和Python实现zip、csv、xls等多格式文件文本内容提取

时间的电影 结局才知道 原来大人已没有童谣 最后的叮咛 最后的拥抱 我们红着眼笑 我们都要把自己照顾好 好到遗憾无法打扰 好好的生活 好好的变老 好好假装我 已经把你忘掉 &#x1f3b5; 五月天《好好》 在进行数据分析、搜索引擎优化或任何需要处理大量…...

C语言如何将多维数组名作为函数参数?

一、问题 ⼦函数执⾏时&#xff0c;整个多维数组是由主函数决定的&#xff0c;这时就要把多维数组的数组名作为函数参数传递给⼦函数。那么在C程序中&#xff0c;怎样将多维数组名作函数参数进⾏传递&#xff1f; 二、解答 以⼆维数组为例&#xff0c;其格式如下。 形参定义&…...

2013年认证杯SPSSPRO杯数学建模C题(第二阶段)公路运输业对于国内生产总值的影响分析全过程文档及程序

2013年认证杯SPSSPRO杯数学建模 C题 公路运输业对于国内生产总值的影响分析 原题再现&#xff1a; 交通运输作为国民经济的载体&#xff0c;沟通生产和消费&#xff0c;在经济发展中扮演着极其重要的角色。纵观几百年来交通运输与经济发展的相互关系&#xff0c;生产水平越高…...

《LeetCode力扣练习》代码随想录——二叉树(合并二叉树---Java)

《LeetCode力扣练习》代码随想录——二叉树&#xff08;合并二叉树—Java&#xff09; 刷题思路来源于 代码随想录 617. 合并二叉树 二叉树-前序遍历 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode…...

openstack云计算(二)——使用Packstack安装器安装一体化OpenStack云平台

初步掌握OpenStack快捷安装的方法。掌握OpenStack图形界面的基本操作。 一【准备阶段】 &#xff08;1&#xff09;准备一台能够安装OpenStack的实验用计算机&#xff0c;建议使用VMware虚拟机。 &#xff08;2&#xff09;该计算机应安装CentOS 7&#xff0c;建议采用CentO…...

Flutter Don‘t use ‘BuildContext‘s across async gaps.

Flutter提示Don‘t use ‘BuildContext‘s across async gaps.的解决办法—flutter里state的mounted属性...

基于SSM+Jsp+Mysql的个性化影片推荐系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…...

循环队列的实现及应用——桶排序bucket_sort、基数排序radix_sort

一、循环队列的实现 代码解释 1、完成初始化 2、定义方法 3、测试实例 4、完整代码 class AQueue:def __init__(self, size=10):self.__mSize = sizeself.__front=0self.__rear = 0self.__listArray = [None] * size#清空元素def clear(self):self.__front = 0self.__rear =…...

ubuntu16如何使用高版本cmake

1.引言 最近在尝试ubuntu16.04下编译开源项目vsome&#xff0c;发现使用apt命令默认安装cmake的的版本太低。如下 最终得知&#xff0c;ubuntu16默认安装确实只能到3.5.1。解决办法只能是源码安装更高版本。 2.源码下载3.20 //定位到opt目录 cd /opt 下载 wget https://cmak…...

电商-广告投放效果分析(KMeans聚类、数据分析-pyhton数据分析

电商-广告投放效果分析&#xff08;KMeans聚类、数据分析&#xff09; 文章目录 电商-广告投放效果分析&#xff08;KMeans聚类、数据分析&#xff09;项目介绍数据数据维度概况数据13个维度介绍 导入库&#xff0c;加载数据数据审查相关性分析数据处理建立模型聚类结果特征分析…...

练习 16 Web [极客大挑战 2019]LoveSQL

extractvalue(1,concat(‘~’, (‘your sql’) ) )报错注入&#xff0c;注意爆破字段的时候表名有可能是table_name不是table_schema 有登录输入框 常规尝试一下 常规的万能密码&#xff0c;返回了一个“admin的密码”&#xff1a; Hello admin&#xff01; Your password is…...

C++——栈和队列容器

前言&#xff1a;这篇文章我们将栈和队列两个容器放在一起进行分享&#xff0c;因为这两个要分享的知识较少&#xff0c;而且两者在结构上有很多相似之处&#xff0c;比如栈只能在栈顶操作&#xff0c;队列只能在队头和队尾操作。 不同于前边所分享的三种容器&#xff0c;这篇…...

Java集合(个人整理笔记)

目录 1. 常见的集合有哪些&#xff1f; 2. 线程安全的集合有哪些&#xff1f;线程不安全的呢&#xff1f; 3. Arraylist与 LinkedList 异同点&#xff1f; 4. ArrayList 与 Vector 区别&#xff1f; 5. Array 和 ArrayList 有什么区别&#xff1f;什么时候该应 Array而不是…...

Redis -- 缓存穿透问题解决思路

缓存穿透 &#xff1a;缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;这些请求都会打到数据库。 常见的解决方案有两种&#xff1a; 缓存空对象 优点&#xff1a;实现简单&#xff0c;维护方便 缺点&#xff1a; 额外…...

数据挖掘中的PCA和KMeans:Airbnb房源案例研究

目录 一、PCA简介 二、数据集概览 三、数据预处理步骤 四、PCA申请 五、KMeans 聚类 六、PCA成分分析 七、逆变换 八、质心分析 九、结论 十、深入探究 10.1 第 1 步&#xff1a;确定 PCA 组件的最佳数量 10.2 第 2 步&#xff1a;使用 9 个组件重做 PCA 10.3 解释 PCA 加载和特…...

【ArcGIS微课1000例】0107:ArcGIS加载在线历史影像服务WMTS

文章目录 一、WMTS历史影像介绍二、ArcGIS加载WMTS服务三、Globalmapper加载WMTS服务一、WMTS历史影像介绍 通过访问历史影响WMTS服务,可以将全球范围内历史影像加载进来,如下所示: WMTS服务: https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WM…...

IP归属地在互联网行业中的应用

摘要&#xff1a;IP&#xff08;Internet Protocol&#xff09;地址归属地是指互联网上某个IP地址所对应的地理位置信息。在互联网行业中&#xff0c;IP归属地具有重要的应用价值&#xff0c;包括网络安全、广告定向、用户定位等方面。IP数据云将探讨IP归属地在互联网行业中的应…...

非关系型数据库-----------探索 Redis高可用 、持久化、性能管理

目录 一、Redis 高可用 1.1什么是高可用 1.2Redis的高可用技术 二、 Redis 持久化 2.1持久化的功能 2.2Redis 提供两种方式进行持久化 三、Redis 持久化之----------RDB 3.1触发条件 3.1.1手动触发 3.1.2自动触发 3.1.3其他自动触发机制 3.2执行流程 3.3启动时加载…...

每日一题:三数之和

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例 1…...

【SCI绘图】【曲线图系列2 python】多类别标签对比的曲线图

SCI&#xff0c;CCF&#xff0c;EI及核心期刊绘图宝典&#xff0c;爆款持续更新&#xff0c;助力科研&#xff01; 本期分享&#xff1a; 【SCI绘图】【曲线图系列2 python】多类别标签对比的曲线图&#xff0c;文末附完整代码。 1.环境准备 python 3 import proplot as pp…...

达梦DMHS-Manager工具安装部署

目录 1、前言 1.1、平台架构 1.2、平台原理 2、环境准备 2.1、硬件环境 2.2、软件环境 2.3、安装DMHS 2.3.1、源端DMHS前期准备 2.3.2、源端DMHS安装 2.3.3、目的端DMHS安装 3、DMHS-Manager客户端部署 3.1、启动dmhs web服务 3.2、登录web管理平台 4、添加DMHS实…...

Marketo营销自动化集成Zoho CRM

Marketo 本身是一种营销自动化工具&#xff0c;可让您根据指定的标准对潜在客户进行评分&#xff0c;并确定哪些潜在客户最有可能进行转化。 CRM 和 Marketo 之间的紧密集成可帮助您规划销售和营销活动&#xff0c;以培育这些高价值潜在客户并最大限度地提高您的团队可以赢得的…...

【Leetcode每日一题】模拟 - 外观数列(难度⭐⭐)(51)

1. 题目解析 题目链接&#xff1a;38. 外观数列 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 所谓“外观数列”&#xff0c;其实只是依次统计字符串中连续且相同的字符的个数。依照题意&#xff0c;依次模拟即 可。…...

CMakeLists.txt编写简单介绍:CMakeLists.txt同时编译.cpp和.cu

关于CMakeLists.txt的相关介绍,这里不赘诉,本人的出发点是借助于CMakeLists.txt掌握基本的C++构建项目流程,下面是本人根据网络资料以及个人实践掌握的资料。 CMakeList.txt构建C++项目 下图是一个使用CUDA实现hello world的项目,一般来说,一个标准的C++项目包括三个文件…...

速卖通网站怎么做推广/微信朋友圈营销方案

转自百科转移概率矩阵&#xff08;又叫跃迁矩阵&#xff0c;英文名&#xff1a;transition matrix&#xff09;是俄国数学家马尔科夫提出的&#xff0c;他在20世纪初发现&#xff1a;一个系统的某些因素在转移中&#xff0c;第n次结果只受第n-1的结果影响&#xff0c;即只与当前…...

建设银行潮州分行网站/seo优化排名经验

半圆区域问题 平面直角坐标系中给定了若干个点&#xff0c;用一个给定圆心和半径的半圆最多能容纳多少个点? Input&#xff1a;给定圆心坐标(x,y)及半径r&#xff0c;然后是坐标系中的点的个数N&#xff0c;接下来的N行就是这N个点的坐标。 Output&#xff1a;输出能容纳的最多…...

制作京东网站建设/今天的新闻发布会

如果你真的就看完了《 packetdrill框架点滴剖析以及TCP重传的一个细节》&#xff0c;我觉得你应该有一个疑问&#xff0c;那就是RH发行版使用的2.6.32内核真的使用了PRR降窗算法吗&#xff1f;为此&#xff0c;我把故事再撸一遍。按照标准的2.6.32内核&#xff0c;第一次收到SA…...

昆明做网站建设的公司哪家好/seo快排技术教程

首先获取两个 nginx 源码包nginx-1.4.7.tar.gznginx-1.6.2.tar.gz------------安装nginx----------# yum install -y gcc gcc-c make //安装gcc由于实验环境缺少编译工具# yum install -y pcre-devel zlib-devel // nginx rewrite gzip 需要依赖的库解压nginx# tar -xzvf n…...

做鸭子的网站/网络销售平台

6.2笔试题目浪潮软件研发B卷(60分钟)注&#xff1a;对于有C和JAVA选择的试题&#xff0c;考生可以选择其中一种解答&#xff0c;请在答题卡中标明。即选择C语言试题解答&#xff0c;则解答的JAVA试题不计分&#xff1b;选择JAVA语言&#xff0c;解答的C语言试题不计分。一、填空…...

wordpress快速安装/百度大数据中心

在写项目时&#xff0c;使用到了express-jwt第三方模块&#xff0c;代码如下&#xff0c; expressJWT({ secret:key.secretKey})然后就报了如下错误&#xff0c; 查阅了npm官网后&#xff0c;才知道最新版本的使用不仅要使用参数secret&#xff0c;还需要参数algorithms。当提…...