QT项目_RPC(进程间通讯)
QT项目_RPC(进程间通讯)
前言:
两个进程间通信、或是说两个应用程序之间通讯。实际情况是在QT开发的一个项目中,里面包含两个子程序,子程序有单独的界面和应用逻辑,这两个子程序跑起来之后需要一些数据的交互,例如:一个程序是用户界面和用户程序,另一个程序时OSD菜单
注意:RPC通讯传输的数据类型有bool、int和std::string(QString不行)
效果演示:
1、移植RCP源码到自己工程
①移植RPC,说白了就是两个文件夹里面有N多个源文件,直接复制过来直接用,需要自行修改.pro文件以便加入编译
# rest_rpc
INCLUDEPATH += $$PWD/msgpack
DEPENDPATH += $$PWD/msgpack
②工程目录
2、源码展示
test_rpc.pro
TEMPLATE = subdirsSUBDIRS += \apply \layer
apply/apply.pro
QT += quick \widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Refer to the documentation for the
# deprecated API to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwidget.cpp \rpc/MessageTip.cpp \rpc/RPCClient.cpp \rpc/RPCServer.cppRESOURCES += qml.qrc# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target# rest_rpc
INCLUDEPATH += $$PWD/msgpack
DEPENDPATH += $$PWD/msgpackHEADERS += \mainwidget.h \rpc/MessageTip.h \rpc/RPCClient.h \rpc/RPCServer.h
apply/Headers/rpc/MessageTip.h
#ifndef MESSAGETIP_H
#define MESSAGETIP_H#include <qstring.h>namespace MessageTip
{void onApplyvalueChanged(int value);void onApplystringChanged(std::string value);
}#endif // MESSAGETIP_H
apply/Headers/rpc/RPCClient.h
#ifndef RPCCLIENT_H
#define RPCCLIENT_H#include "rest_rpc/rpc_client.hpp"class RPCClient
{
public:RPCClient();static RPCClient *get_instance(){static RPCClient manage;return &manage;}/*** @brief 尝试连接RPC Server* @return true 连接成功,false 连接失败*/void tryConnect();rest_rpc::rpc_client *getSocketObject();private:rest_rpc::rpc_client *m_pClient = nullptr;
};#endif // RPCCLIENT_H
apply/Headers/rpc/RPCServer.h
#ifndef RPCSERVER_H
#define RPCSERVER_H#include <qstring.h>
#include "rest_rpc/rpc_server.h"using namespace rest_rpc;
using namespace rpc_service;class RPCServer
{
public:RPCServer();void setApplyvalue(rpc_conn conn , int value);void setApplystring(rpc_conn conn , std::string value);
};#endif // RPCSERVER_H
apply/Headers/mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H#include <QObject>
#include <QWidget>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include "rpc/RPCServer.h"class MainWidget : public QObject
{Q_OBJECT
public:MainWidget();protected slots:void onClickPageNo(bool enable);void onApplyvalueChanged(int value);void onApplystringChanged(QString value);private:QQuickItem *m_applyItem = nullptr;QObject *m_applyObject = nullptr;RPCServer *m_pRPCServer = nullptr;
};#endif // MAINWIDGET_H
apply/Sources/rpc/MessageTip.cpp
#include "MessageTip.h"
#include "RPCClient.h"
#include "qdebug.h"void MessageTip::onApplyvalueChanged(int value)
{try {RPCClient::get_instance()->getSocketObject()->call<void>("MessageTip::layervalueChanged", value);} catch (const std::exception &e) {qDebug() << "Exception {}", e.what();}
}void MessageTip::onApplystringChanged(std::string value)
{try {RPCClient::get_instance()->getSocketObject()->call<void>("MessageTip::layerstringChanged", value);} catch (const std::exception &e) {qDebug() << "Exception {}", e.what();}
}
apply/Sources/rpc/RPCClient.cpp
#include "RPCClient.h"
#include <QtDebug>RPCClient::RPCClient()
{}void RPCClient::tryConnect()
{m_pClient = new rest_rpc::rpc_client("127.0.0.1", 9000);m_pClient->enable_auto_reconnect(true);m_pClient->connect();std::thread([&] {while (true){if (m_pClient->has_connected()) {qDebug() << "apply RPC connect success";break;} else {qDebug() << "apply RPC connect fail";std::this_thread::sleep_for(std::chrono::milliseconds(500));}}}).detach();
}rest_rpc::rpc_client *RPCClient::getSocketObject()
{return m_pClient;
}
apply/Sources/rpc/RPCServer.cpp
#include "RPCServer.h"
#include "qdebug.h"RPCServer::RPCServer()
{std::thread([&] {rpc_server server(9001, std::thread::hardware_concurrency());server.register_handler("MessageTip::setApplyvalue", &RPCServer::setApplyvalue, this);server.register_handler("MessageTip::setApplystring", &RPCServer::setApplystring, this);server.run();}).detach();
}void RPCServer::setApplyvalue(rpc_conn conn , int value)
{//todoqDebug() << "apply recv :" << value;
}void RPCServer::setApplystring(rpc_conn conn , std::string value)
{//todoqDebug() << "apply recv :" << QString::fromStdString(value);
}
apply/Sources/main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "mainwidget.h"
#include "qdebug.h"
#include "qthread.h"int main(int argc, char *argv[])
{QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);// QQmlApplicationEngine engine;
// const QUrl url(QStringLiteral("qrc:/main.qml"));
// QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
// &app, [url](QObject * obj, const QUrl & objUrl) {
// if (!obj && url == objUrl) {
// QCoreApplication::exit(-1);
// }
// }, Qt::QueuedConnection);
// engine.load(url);MainWidget mainwidget;return app.exec();
}
apply/Sources/mainwidget.cpp
#include "mainwidget.h"
#include "qdebug.h"
#include "rpc/RPCClient.h"
#include "rpc/MessageTip.h"
#include <QProcess>MainWidget::MainWidget()
{QQmlApplicationEngine *m_pEngine = new QQmlApplicationEngine;QQmlComponent component(m_pEngine, QUrl(QStringLiteral("qrc:/main.qml")));QObject *mainObject = component.create();if (mainObject == nullptr) {qDebug() << "mainObject fail";return;}QList<QObject *> objectList = mainObject->findChildren<QObject *>("mybutton");if (objectList.isEmpty()) {qDebug() << "mybutton failed\n";return;}m_applyObject = objectList.last();connect(m_applyObject, SIGNAL(applyvalueChanged(int)), this, SLOT(onApplyvalueChanged(int)));connect(m_applyObject, SIGNAL(applystringChanged(QString)), this, SLOT(onApplystringChanged(QString)));connect(mainObject, SIGNAL(window_interface(bool)), this, SLOT(onClickPageNo(bool)));m_pRPCServer = new RPCServer();RPCClient::get_instance()->tryConnect();
}void MainWidget::onClickPageNo(bool enable)
{QProcess *process = new QProcess();process->start("/home/zhou/work/test/build-test_rpc-Desktop_Qt_5_14_2_GCC_64bit-Debug/layer/layer");
}void MainWidget::onApplyvalueChanged(int value)
{qDebug() << "onApplyvalueChanged" << value;MessageTip::onApplyvalueChanged(value);
}void MainWidget::onApplystringChanged(QString value)
{qDebug() << "onApplystringChanged" << value;MessageTip::onApplystringChanged(std::string(value.toLocal8Bit()));
}
apply/main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12Window {visible: truewidth: 640height: 480objectName: "apply_window"title: qsTr("Hello apply")signal window_interface(bool enable)Column{anchors.fill: parentspacing: 20Button{width: 140height: 50text: "开启界面2"onClicked: {window_interface(true)}}Mybutton{width: 140height: 300}}
}
apply/Mybutton.qml
import QtQuick 2.0
import QtQuick.Controls 2.12Item {objectName: "mybutton"signal applyvalueChanged(int value)signal applystringChanged(string value)Column{spacing: 10Button{objectName: "button"width: 140height: 50text: "send1"onClicked: {applyvalueChanged(1)}}Button{width: 140height: 50text: "send2"onClicked: {applyvalueChanged(2)}}Button{width: 140height: 50text: "验证string"onClicked: {applystringChanged("{\"name\":\"lili\",\"age\":24,\"class\":6}")}}}
}
layer.pro
QT += quick
QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Refer to the documentation for the
# deprecated API to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwidget.cpp \rpc/MessageTip.cpp \rpc/RPCClient.cpp \rpc/RPCServer.cppRESOURCES += qml.qrc# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target# rest_rpc
INCLUDEPATH += $$PWD/msgpack
DEPENDPATH += $$PWD/msgpackHEADERS += \mainwidget.h \rpc/MessageTip.h \rpc/RPCClient.h \rpc/RPCServer.h
layer/Headers/rpc/MessageTip.h
#ifndef MESSAGETIP_H
#define MESSAGETIP_H#include <qstring.h>namespace MessageTip
{void setApplyvalue(int value);void setApplystring(std::string value);
}#endif // MESSAGETIP_H
layer/Headers/rpc/RPCClient.h
#ifndef RPCCLIENT_H
#define RPCCLIENT_H#include "rest_rpc/rpc_client.hpp"class RPCClient
{
public:RPCClient();static RPCClient *get_instance(){static RPCClient layer_manage;return &layer_manage;}/*** @brief 尝试连接RPC Server* @return true 连接成功,false 连接失败*/void tryConnect();rest_rpc::rpc_client *getSocketObject();private:rest_rpc::rpc_client *m_pClient = nullptr;
};#endif // RPCCLIENT_H
layer/Headers/rpc/RPCServer.h
#ifndef RPCSERVER_H
#define RPCSERVER_H#include <QtDebug>
#include <QThread>
#include <QObject>
#include <QQuickItem>#include "rest_rpc/rpc_server.h"
using namespace rest_rpc;
using namespace rpc_service;class RPCServer : public QObject
{Q_OBJECT
public:explicit RPCServer(QObject *parent = nullptr);void layervalueChanged(rpc_conn conn , int value);void layerstringChanged(rpc_conn conn , std::string value);protected:signals:private:QObject *m_pMainObject = nullptr;QQuickItem *m_pOSDAreaItem = nullptr;
};#endif // RPCSERVER_H
layer/Headers/mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H#include <QObject>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include "rpc/RPCServer.h"class mainwidget : public QObject
{Q_OBJECT
public:mainwidget();private:RPCServer *m_pRPCServer = nullptr;
};#endif // MAINWIDGET_H
layer/Sources/rpc/MessageTip.cpp
#include "MessageTip.h"
#include "RPCClient.h"
#include <QtDebug>void MessageTip::setApplyvalue(int value)
{try {return RPCClient::get_instance()->getSocketObject()->call<void>("MessageTip::setApplyvalue", value);} catch (const std::exception &e) {qDebug() << "setImageRotate exception" << e.what();}
}void MessageTip::setApplystring(std::string value)
{try {return RPCClient::get_instance()->getSocketObject()->call<void>("MessageTip::setApplystring", value);} catch (const std::exception &e) {qDebug() << "setImageRotate exception" << e.what();}
}
layer/Sources/rpc/RPCClient.cpp
#include "RPCClient.h"
#include <QtDebug>RPCClient::RPCClient()
{}void RPCClient::tryConnect()
{
//#if defined(__x86_64)
// m_pClient = new rest_rpc::rpc_client("192.168.31.95", 9001);
//#elsem_pClient = new rest_rpc::rpc_client("127.0.0.1", 9001);
//#endifm_pClient->enable_auto_heartbeat(true);m_pClient->connect();std::thread([&] {while (true){qDebug() << "layer RPC connect fail";if (m_pClient->has_connected()) {qDebug() << "layer RPC connect success";break;} else {std::this_thread::sleep_for(std::chrono::milliseconds(500));qDebug() << "layer RPC connect fail";}}}).detach();
}rest_rpc::rpc_client *RPCClient::getSocketObject()
{return m_pClient;
}
layer/Sources/rpc/RPCServer.cpp
#include "RPCServer.h"
#include "rpc/MessageTip.h"RPCServer::RPCServer(QObject *parent) : QObject(parent)
{QThread::create([&] {rpc_server server(9000, std::thread::hardware_concurrency());server.register_handler("MessageTip::layervalueChanged", &RPCServer::layervalueChanged, this);server.register_handler("MessageTip::layerstringChanged", &RPCServer::layerstringChanged, this);server.run();})->start();qDebug() << "start rpc server";
}void RPCServer::layervalueChanged(rpc_conn conn , int value)
{//todoMessageTip::setApplyvalue(value);qDebug() << "APPLY SEND :" << value;
}void RPCServer::layerstringChanged(rpc_conn conn , std::string value)
{//todoMessageTip::setApplystring(value);qDebug() << "APPLY SEND :" << QString::fromStdString(value);
}
layer/Sources/main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "qdebug.h"
#include "mainwidget.h"int main(int argc, char *argv[])
{QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QGuiApplication app(argc, argv);// QQmlApplicationEngine engine;
// const QUrl url(QStringLiteral("qrc:/main.qml"));
// QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
// &app, [url](QObject * obj, const QUrl & objUrl) {
// if (!obj && url == objUrl) {
// QCoreApplication::exit(-1);
// }
// }, Qt::QueuedConnection);
// engine.load(url);mainwidget mainwidget;return app.exec();
}
layer/Sources/mainwidget.cpp
#include "mainwidget.h"
#include "rpc/RPCClient.h"mainwidget::mainwidget()
{QQmlApplicationEngine *m_pEngine = new QQmlApplicationEngine;QQmlComponent component(m_pEngine, QUrl(QStringLiteral("qrc:/main.qml")));QObject *mainObject = component.create();if (mainObject == nullptr) {qDebug() << "mainObject fail";return;}m_pRPCServer = new RPCServer();RPCClient::get_instance()->tryConnect();
}
layer/main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12Window {visible: truewidth: 640height: 480title: qsTr("Hello layer")Column{anchors.fill: parentspacing: 20Button{width: 140height: 50text: "layer +"}Button{width: 140height: 50text: "layer -"}}
}相关文章:
QT项目_RPC(进程间通讯)
QT项目_RPC(进程间通讯) 前言: 两个进程间通信、或是说两个应用程序之间通讯。实际情况是在QT开发的一个项目中,里面包含两个子程序,子程序有单独的界面和应用逻辑,这两个子程序跑起来之后需要一些数据的交互,例如&…...
移动硬盘文件丢失怎么恢复?
在我们的日常工作、学习和生活都离不开各种数据。每天都会接收或处理各种数据,尤其是做设计、自媒体、多媒体设计的人。移动硬盘成为我们常备的存储工具,但有使用就会伴随着意外情况的发生,这将导致移动硬盘上数据的丢失,比如误删…...
什么是同步整流和异步整流
在设计降压型DCDC电路的时候,经常会听到同步整流(synchronous)和异步整流(asynchronous)。那么什么是同步整流,什么是异步整流呢从这两种电路的拓扑来看,异步整流型外围有一个续流二极管&#x…...
关于PYTHON Enclosing 的一个小问题
问题分析 以下是一段每隔半小时重复执行测试用例的脚本,func是传入的测试函数,在执行func前后,会打印操作次数 def repeat(func, action):try:log.info(u******开始并发%s****** % action)thread_list []for i in range(repeat_count):def…...
LabVIEW错误-2147220623:最大内存块属性不存在
LabVIEW错误-2147220623:最大内存块属性不存在在使用NI Linux实时操作系统目标中,使用系统属性节点和分布式系统管理器(DSM),但遇到一些问题:它未正确报告系统上的可用物理内存量。在NI Linux实时系统上出现…...
图的总复习
一、图的定义Graph 图是由顶点vertex集合及顶点间关系集合组成的一种数据结构: 顶点的集合 和 边的集合 二、无向图 用(x,y)表示两个顶点x和y之间的一条边(edge) 边是无方向的 N{V,E},V{0…...
测试流程记录
1,需求评审 2,技术方案评审 3,编写测试用例 编写需求分析 编写测试用例 编写冒烟case 4,用例评审 5,提测 提测前给开发执行冒烟case 6,测试 测试完成前约产品验收时间 7,验收 跟进验收问题…...
Mysql主从架构与实例
mysql的主从架构 MySQL主从架构是一种常见的数据库高可用性解决方案,它通常由一个主数据库和多个从数据库组成。主数据库用于处理写入请求和读取请求,从数据库则用于处理只读请求。 在主从架构中,主数据库记录所有数据更改并将这些更改同步…...
webpack(高级)--Tapable
webpack 我们直到webpack中有两个非常重要的类Compiler和Compilation 他们通过注入插件的方式 来监听webpack的所有声明周期 插件的注入是通过创建Tapable库中的各种Hook的实例来得到 Tapable Tapable中的Hook分为同步与异步 同步 SyncHook SyncBailHook SyncWaterfallHook…...
Python常见类型转换合集
近期在工作中常常接触到各种转换,如字符串转byte,byte转字符串,还有byte数组转成报文能接纳的格式(bin格式的十六进制)。故有必要系统的总结一下Python中常见的类型转换。 一:常见类型的概念 类型举例说明…...
知识点(1)
什么是跨域请求? 当前发起请求的域与该请求指向的资源所在的域不一样,凡是发送请求的url的协议、域名、端口号三者之间任意一者与当前页面地址不同的请求。这里的域指的是:我们认为若协议域名端口号均相同,那么就是同域。 get和…...
Tomcat源码分析-启动分析(三) Catalina启动
在上一篇文章中,我们分析了tomcat的初始化过程,是由Bootstrap反射调用Catalina的load方法完成tomcat的初始化,包括server.xml的解析、实例化各大组件、初始化组件等逻辑。那么tomcat又是如何启动webapp应用,又是如何加载应用程序的…...
程序员必备的软技能-金字塔原理拆解
前言 日常工作中,常常因为思维、表达方式不对产生不想要的结果: 写了一个小时的周报,领导却不满意?跟团队讲了半天自己的想法,可别人就是没理解?看了很多知识、信息,却一点也没记住࿱…...
基金详细介绍
投资回报率 利润 / 投资总额(第一次投资回报率 5%) 关注南方理财 60 天债券 B(202306)万元收益 50—60 元 购基七步曲: 风险测试基本知识交易指南查看业绩了解评级在线下单赎回 基金类型: 积极成长型基金…...
媒体邀约之企业如何加强品牌的宣传力度
传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。胡老师分享了许多媒体传播方面的经验,今天就跟大家分享下我对企业宣传方面的看法。企业如何加强品牌的宣传力度:1,网络宣传在社交媒体上建立企业账户&am…...
【SpringBoot】75、SpringBoot中使用spring-retry轻松解决重试
在日常开发过程中,难免会与第三方接口发生交互,例如:短信发送、远程服务调用、争抢锁等场景,当正常调用发生异常时,例如:网络抖动,这些间歇性的异常在一段时候之后会自行恢复,程序为…...
网络工程师必知的几个问题
路由器问题: 1、什么时候使用多路由协议? 当两种不同的路由协议要交换路由信息时,就要用到多路由协议。当然,路由再分配也可以交换路由信息。下列情况不必使用多路由协议: 从老版本的内部网关协议( interi…...
【仓库管理】搭建 Maven 私服之一--Nexus仓库(Repository)管理软件
文章目录Nexus是什么Nexus下载和安装1. 进入 Nexus 2.x 下载页面,根据本机操作系统,选择对应的版本进行下载,如下图所示。2. 将下载 Nexus 安装包解压到本地磁盘,可获得 nexus-2.14.20-02 和 sonatype-work 2 个目录,如…...
凹凸贴图(Bump Mapping)
凹凸贴图是什么? 我们首先来看low-poly(多边形数较少)mesh和high-poly(多边形数量较多)mesh之间的不同。首先,最明显的不同就是high-poly能够表现出更多细节,但high-poly有比较大的性能开销。有…...
文华财经期货指标公式量化策略分析软件,多空共振信号准确率高的公式源码
期货指标公式信号本身就有滞后性,周期越大,滞后性越久。指标公式不是100%稳赚的工具,只是在合适的时候让我们理性看待行情,减少逆势操作。 多空量化三维系统是一款通过数学分析、挖掘价格运动规律,对历史价格走势、趋势…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...




