Qt之进程通信-IPC(QLocalServer,QLocalSocket 含源码+注释)

文章目录

  • 一、IPC通信示例图
    • 1.1 设置关键字并连接的示例图
    • 1.2 进程间简单的数据通信示例图
    • 1.3 断开连接的示例图
      • 1.3.1 由Server主动断开连接
      • 1.3.2 由Socket主动断开连接
  • 1.4 Server停止监听后的效果
  • 二、个人理解与一些心得
  • 三、一些疑问(求教 家人们😂)
  • 四、源码
    • CMainWindowServer
      • CMainWindowServer.h
      • CMainWindowServer.cpp
      • CMainWindowServer.ui
    • CMainWindowSocket
      • CMainWindowSocket.h
      • CMainWindowSocket.cpp
      • CMainWindowSocket.ui
  • 总结
  • 相关文章

一、IPC通信示例图

1.1 设置关键字并连接的示例图

如下,分别在各个界面的关键字控件中填入key,依次连接。
请添加图片描述

1.2 进程间简单的数据通信示例图

如下,简单演示了server与全部、指定socket通信及接收socket发送的数据。
请添加图片描述

1.3 断开连接的示例图

1.3.1 由Server主动断开连接

如下,演示了单独断开一个及断开全部的操作,其中断开操作是由server发送数据通知socket断开,server这边则等待断开返回。
请添加图片描述

1.3.2 由Socket主动断开连接

如下演示了socket程序主动断开的操作
请添加图片描述

1.4 Server停止监听后的效果

如下,演示了server停止监听后仍可以与已经连接过的socket的通信的效果。
请添加图片描述

二、个人理解与一些心得

  1. 若要使用QLocalServer/QLocalSocket,需要在 pro添加network模块(添加这一行QT += network)。
  2. 在我个人使用中发现,在同一进程中,调用socket的write是不会触发当前进程的readyRead信号链接的信号槽。
  3. 在QLocalServer停止监听后不会影响已经连接好的Socket对象,因为QLocalServer的close仅负责停止监听,并不断开。

三、一些疑问(求教 家人们😂)

  1. 在帮助中又下方的帮助代码,但是在本地测试发现不能先调用disconnectFromServer,后面的waitForDisconnected总是拿不到状态。
	socket->disconnectFromServer();if (socket->waitForDisconnected(1000))qDebug("Disconnected!");
  1. 以及在个人理解中的第2点也存在一些疑问

四、源码

CMainWindowServer

CMainWindowServer.h

#ifndef CMAINWINDOWSERVER_H
#define CMAINWINDOWSERVER_H#include <QMainWindow>
#include <QLocalServer>namespace Ui {
class CMainWindowServer;
}class QLocalSocket;
class CMainWindowServer : public QMainWindow
{Q_OBJECTpublic:explicit CMainWindowServer(QWidget *parent = nullptr);~CMainWindowServer();private:/*** @brief disconnectSocketByStr 指定socket断开函数(复用)* @param socketStr 指定的socket套接字字符串*/void disconnectSocketByStr(const QString &socketStr);private slots:/*** @brief on_btnListen_clicked 开始监听按钮*/void on_btnListen_clicked();/*** @brief on_btnStopListen_clicked 停止监听按钮*/void on_btnStopListen_clicked();/*** @brief on_newConnection 新连接槽函数*/void on_newConnection();/*** @brief on_socketReadyRead 数据接收槽函数*/void on_socketReadyRead();/*** @brief on_btnDisconnectSocket_clicked 断开socket槽函数*/void on_btnDisconnectSocket_clicked();/*** @brief on_btnSend_clicked 数据发送按钮*/void on_btnSend_clicked();private:Ui::CMainWindowServer *ui;QLocalServer            m_localServer;          // 通信服务对象QList<QLocalSocket *>   m_listLocalSockets;     //  本地套接字列表
};#endif // CMAINWINDOWSERVER_H

CMainWindowServer.cpp

#include "CMainWindowServer.h"
#include "ui_CMainWindowServer.h"#include <QLocalServer>
#include <QMessageBox>
#include <QLocalSocket>
#include <QDebug>
#include <QTimer>CMainWindowServer::CMainWindowServer(QWidget *parent) :QMainWindow(parent),ui(new Ui::CMainWindowServer)
{ui->setupUi(this);// 关联套接字连接槽函数connect(&m_localServer, &QLocalServer::newConnection, this, &CMainWindowServer::on_newConnection);
}CMainWindowServer::~CMainWindowServer()
{delete ui;
}void CMainWindowServer::disconnectSocketByStr(const QString &socketStr)
{// 强转当前指针字符串或者socket指针对象QLocalSocket *socket = (QLocalSocket *)socketStr.toUInt();// 判断是否存在于socket容器中if(m_listLocalSockets.contains(socket)) {// 发送关闭提示给socketsocket->write(u8"服务器断开!");// 等待3000毫秒接收断开链接的信息if(!socket->waitForDisconnected(3000)) {QMessageBox::information(this, u8"提示", "断开超时");}else {// 移除当前位置的控件QMessageBox::information(this, u8"提示", "断开成功");// 移除当前指定的ui->comboBoxSockets->removeItem(ui->comboBoxSockets->findText(socketStr));m_listLocalSockets.removeOne(socket);}}else {QMessageBox::information(this, u8"提示", socketStr + u8"地址无记录");}
}void CMainWindowServer::on_btnListen_clicked()
{QString listenKey = ui->lineEditListenKey->text();// 获取是否监听成功bool flag =  m_localServer.listen(listenKey);if(!flag) {QMessageBox::information(this, u8"提示", m_localServer.errorString());}else {QMessageBox::information(this, u8"提示", u8"监听成功");// 监听后‘开始监听’按钮禁用,‘停止监听’按钮启用ui->btnListen->setEnabled(false);ui->btnStopListen->setEnabled(true);}
}void CMainWindowServer::on_btnStopListen_clicked()
{m_localServer.close();if(!m_localServer.isListening()) {QMessageBox::information(this, u8"提示", u8"停止监听成功");// 停止监听后‘开始监听’按钮启用,‘停止监听’按钮禁用ui->btnListen->setEnabled(true);ui->btnStopListen->setEnabled(false);}else {QMessageBox::information(this, u8"提示", u8"停止监听失败");}
}void CMainWindowServer::on_newConnection()
{// 判断是否存在新的socket连接if(m_localServer.hasPendingConnections()) {// 获取套接字对象QLocalSocket *socketTmp = m_localServer.nextPendingConnection();// 套接字对象添加到套接字容器中m_listLocalSockets.append(socketTmp);// 套接字地址转为数值QString socketStr = QString::number((uint64_t)socketTmp);// 套接字文本添加到下拉列表中并在界面做出连接提示ui->comboBoxSockets->addItem(socketStr);ui->textEdit->append(socketStr + "加入连接!");// 关联新数据的信号槽connect(socketTmp, &QLocalSocket::readyRead, this, &CMainWindowServer::on_socketReadyRead);}
}void CMainWindowServer::on_socketReadyRead()
{// 获取发送信号的对象QLocalSocket *curSocket = dynamic_cast<QLocalSocket *>(sender());// 将数据直接读取并添加到多行文本框中ui->textEdit->append(QString::number((uint64_t)curSocket) + ":" + curSocket->readAll());
}void CMainWindowServer::on_btnDisconnectSocket_clicked()
{// 获取将要断开的文本并弹出断开提示QString socketStr = ui->comboBoxSockets->currentText();QMessageBox::StandardButton flag = QMessageBox::information(this, u8"提示", u8"是否断开" + socketStr + "?");if(QMessageBox::Ok != flag) {return;}// 根据断开文本做不不同断开操作if(0 == socketStr.compare(u8"全部")) {foreach(QLocalSocket *socket, m_listLocalSockets) {disconnectSocketByStr(QString::number((uint64_t)socket));}}else {disconnectSocketByStr(socketStr);}
}void CMainWindowServer::on_btnSend_clicked()
{// 获取将要接收数据的识别文本QString socketStr = ui->comboBoxSockets->currentText();// 获取将要发送的数据QString data = ui->textEditSendData->toPlainText();// 根据识别文本做出不同的操作if(0 == socketStr.compare(u8"全部")) {foreach(QLocalSocket *socket, m_listLocalSockets) {socket->write(data.toUtf8());}}else {// 直接将当前文本强转为套接字对象(因为该文本为指针地址强转而来)QLocalSocket *socket = (QLocalSocket *)socketStr.toUInt();if(m_listLocalSockets.contains(socket)) {socket->write(data.toUtf8());}else {QMessageBox::information(this, u8"提示", socketStr + "地址找不到");}}}

CMainWindowServer.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>CMainWindowServer</class><widget class="QMainWindow" name="CMainWindowServer"><property name="geometry"><rect><x>0</x><y>0</y><width>340</width><height>420</height></rect></property><property name="windowTitle"><string>CMainWindow</string></property><widget class="QWidget" name="centralWidget"><layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,3,1,0"><item><layout class="QHBoxLayout" name="horizontalLayout"><item><widget class="QLineEdit" name="lineEditListenKey"/></item><item><widget class="QPushButton" name="btnListen"><property name="text"><string>监听</string></property></widget></item><item><widget class="QPushButton" name="btnStopListen"><property name="enabled"><bool>false</bool></property><property name="text"><string>停止监听</string></property></widget></item></layout></item><item><layout class="QHBoxLayout" name="horizontalLayout_3"><item><widget class="QComboBox" name="comboBoxSockets"><item><property name="text"><string>全部</string></property></item></widget></item><item><widget class="QPushButton" name="btnDisconnectSocket"><property name="text"><string>断开当前链接选项</string></property></widget></item></layout></item><item><widget class="QTextEdit" name="textEdit"/></item><item><widget class="QTextEdit" name="textEditSendData"/></item><item><layout class="QHBoxLayout" name="horizontalLayout_2"><item><spacer name="horizontalSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item><item><widget class="QPushButton" name="btnSend"><property name="text"><string>发送</string></property></widget></item></layout></item></layout></widget><widget class="QMenuBar" name="menuBar"><property name="geometry"><rect><x>0</x><y>0</y><width>340</width><height>23</height></rect></property></widget><widget class="QToolBar" name="mainToolBar"><attribute name="toolBarArea"><enum>TopToolBarArea</enum></attribute><attribute name="toolBarBreak"><bool>false</bool></attribute></widget><widget class="QStatusBar" name="statusBar"/></widget><layoutdefault spacing="6" margin="11"/><resources/><connections/>
</ui>

CMainWindowSocket

CMainWindowSocket.h

#ifndef CMAINWINDOWSOCKET_H
#define CMAINWINDOWSOCKET_H#include <QMainWindow>
#include <QLocalSocket>namespace Ui {
class CMainWindowSocket;
}class CMainWindowSocket : public QMainWindow
{Q_OBJECTpublic:explicit CMainWindowSocket(QWidget *parent = nullptr);~CMainWindowSocket();private slots:/*** @brief on_btnConnect_clicked 连接按钮信号槽*/void on_btnConnect_clicked();/*** @brief on_btnSend_clicked 发送按钮信号槽*/void on_btnSend_clicked();/*** @brief on_btnDisConnected_clicked 断开连接信号槽*/void on_btnDisConnected_clicked();/*** @brief on_socketReadyRead 数据接收信号槽*/void on_socketReadyRead();private:Ui::CMainWindowSocket *ui;QLocalSocket    m_localSocket;  // 套接字对象
};#endif // CMAINWINDOWSOCKET_H

CMainWindowSocket.cpp

#include "CMainWindowSocket.h"
#include "ui_CMainWindowSocket.h"#include <QMessageBox>
#include <QTimer>CMainWindowSocket::CMainWindowSocket(QWidget *parent) :QMainWindow(parent),ui(new Ui::CMainWindowSocket)
{ui->setupUi(this);// 关联数据接收信号槽connect(&m_localSocket, &QLocalSocket::readyRead, this, &CMainWindowSocket::on_socketReadyRead);
}CMainWindowSocket::~CMainWindowSocket()
{delete ui;
}void CMainWindowSocket::on_btnConnect_clicked()
{// 根据key连接服务m_localSocket.connectToServer(ui->lineEditConnectKey->text());// 等待一秒是否连接成功if(m_localSocket.waitForConnected(1000)) {QString tip = u8"连接成功";// 连接成功后打开读写通道if(!m_localSocket.open(QIODevice::ReadWrite)) {tip.append(QString(u8",但Socket读写打开失败(%1)").arg(m_localSocket.errorString()));}QMessageBox::information(this, u8"提示", tip);// 连接后‘连接’按钮禁用,‘断开连接’按钮启用ui->btnConnect->setEnabled(false);ui->btnDisConnected->setEnabled(true);}else {QMessageBox::information(this, u8"提示", u8"连接失败");}
}void CMainWindowSocket::on_btnSend_clicked()
{// 写入数据m_localSocket.write(ui->textEditSendData->toPlainText().toUtf8());// 等待写入信号,若未写入成功弹出提示if(!m_localSocket.waitForBytesWritten(100)) {QMessageBox::information(this, u8"提示", m_localSocket.errorString());}
}void CMainWindowSocket::on_btnDisConnected_clicked()
{if(QLocalSocket::ConnectedState == m_localSocket.state()) {m_localSocket.write(QString(u8"%1已断开!").arg((uint64_t)this).toUtf8());m_localSocket.disconnectFromServer();// 断开连接后‘连接’按钮启用,‘断开连接’按钮禁用ui->btnConnect->setEnabled(true);ui->btnDisConnected->setEnabled(false);}else {QMessageBox::information(this, u8"提示", u8"断开失败,当前并非连接状态!" );}
}void CMainWindowSocket::on_socketReadyRead()
{// 读取索引数据QString data = m_localSocket.readAll();// 识别数据文本,当复合条件是断开连接if(0 == data.compare(u8"服务器断开!")) {on_btnDisConnected_clicked();}ui->textEdit->append(data);
}

CMainWindowSocket.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>CMainWindowSocket</class><widget class="QMainWindow" name="CMainWindowSocket"><property name="geometry"><rect><x>0</x><y>0</y><width>300</width><height>420</height></rect></property><property name="windowTitle"><string>CMainWindowSocket</string></property><widget class="QWidget" name="centralWidget"><layout class="QVBoxLayout" name="verticalLayout" stretch="0,3,1,0"><item><layout class="QHBoxLayout" name="horizontalLayout"><item><widget class="QLineEdit" name="lineEditConnectKey"/></item><item><widget class="QPushButton" name="btnConnect"><property name="text"><string>连接</string></property></widget></item><item><widget class="QPushButton" name="btnDisConnected"><property name="enabled"><bool>false</bool></property><property name="text"><string>断开连接</string></property></widget></item></layout></item><item><widget class="QTextEdit" name="textEdit"/></item><item><widget class="QTextEdit" name="textEditSendData"/></item><item><layout class="QHBoxLayout" name="horizontalLayout_2"><item><spacer name="horizontalSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item><item><widget class="QPushButton" name="btnSend"><property name="text"><string>发送</string></property></widget></item></layout></item></layout></widget><widget class="QMenuBar" name="menuBar"><property name="geometry"><rect><x>0</x><y>0</y><width>300</width><height>23</height></rect></property></widget><widget class="QToolBar" name="mainToolBar"><attribute name="toolBarArea"><enum>TopToolBarArea</enum></attribute><attribute name="toolBarBreak"><bool>false</bool></attribute></widget><widget class="QStatusBar" name="statusBar"/></widget><layoutdefault spacing="6" margin="11"/><resources/><connections/>
</ui>

总结

在使用QLocalServer和QLocalSocket的过程中,发现QLocalSocket不是数据通道的持有对象,而是数据通道本身(如共享内存是通过data获取共享内存的地址,而QLocalSocket是直接调用write写入,当然和他的继承有关系),而相对来说QLocalServer更像使用者。不过IPC相对于共享内存来说可能有及时性的特点,因为数据一来IPC就直接读取,而共享内存则是需要定时读取数据。

相关文章

Qt之进程通信-共享内存(含源码+注释)

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 ^o^/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/117622.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ES6】JavaScript的Proxy:理解并实现高级代理功能

在JavaScript中&#xff0c;Proxy是一种能够拦截对对象的读取、设置等操作的机制。它们提供了一种方式&#xff0c;可以在执行基本操作之前或之后&#xff0c;对这些操作进行自定义处理。这种功能在许多高级编程场景中非常有用&#xff0c;比如实现数据验证、日志记录、权限控制…

【网络教程】群晖如何正确的安装openwrt旁路由

文章目录 准备安装导入镜像创建虚拟机访问旁路由旁路由网络设置准备 我这里的环境是群晖DSM7.2版本首先大家需要预先安装套件Virtual Machine Manager,这里就省略了 根据个人需求去下载openwrt的固件,下载的时候选择x86的img镜像文件,这里也可以直接使用我使用的这个固件(资…

RISC-V 中国峰会 | OpenMPL引人注目,RISC-V Summit China 2023圆满落幕

RISC-V中国峰会圆满落幕 2023年8月25日&#xff0c;为期三天的RISC-V中国峰会&#xff08;RISC-V Summit China 2023&#xff09;圆满落幕。本届峰会以“RISC-V生态共建”为主题&#xff0c;结合当下全球新形势&#xff0c;把握全球新时机&#xff0c;呈现RISC-V全球新观点、新…

8.27周报

文章目录 前言论文阅读摘要介绍模型算法 总结 前言 本周学习了GAN论文《Generative Adversarial Nets》&#xff0c;了解GAN主要由两部分组成&#xff1a;生成器和判别器&#xff0c;知道生成器G和判别器D的作用及原理&#xff0c;相比于其他的生成模型&#xff0c;了解GAN的优…

Postman的高级用法—Runner的使用​

1.首先在postman新建要批量运行的接口文件夹&#xff0c;新建一个接口&#xff0c;并设置好全局变量。 2.然后在Test里面设置好要断言的方法 如&#xff1a; tests["Status code is 200"] responseCode.code 200; tests["Response time is less than 10000…

自建音乐播放器之一

这里写自定义目录标题 1.1 官方网站 2. Navidrome 简介2.1 简介2.2 特性 3. 准备工作4. 视频教程5. 界面演示5.1 初始化页5.2 专辑页 前言 之前给大家介绍过 Koel 音频流服务&#xff0c;就是为了解决大家的这个问题&#xff1a;下载下来的音乐&#xff0c;只能在本机欣赏&…

零基础学Python:元组(Tuple)详细教程

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 Python的元组与列表类似&#xff0c; 不同之处在于元组的元素不能修改, 元组使用小括号,列表使用方括号, 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可 &#x1f447; &#x1f447; &#x1f447; 更…

软件外包开发人员分类

在软件开发中&#xff0c;通常会分为前端开发和后端开发&#xff0c;下面和大家分享软件开发中的前端开发和后端开发分类和各自的职责&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1. 前端开发&…

【C语言】冒泡排序的快排模拟

说到排序&#xff0c;必然绕不开两个排序&#xff0c;冒泡排序与快速排序 冒泡排序是大多数人的启蒙排序&#xff0c;因为他的算法简单。但效率不高&#xff0c;便于新手理解&#xff1b; 而快速排序是集大成之作&#xff0c;效率最高&#xff0c;使用最为广泛。 今天这篇文章带…

单片机-芯片怎么看图连接

单片机连接数码管 硬件连接线路图 单片机中的IO口连接端子 J25 &#xff0c;J25 连接 2个电阻 PR14 &#xff0c;引出管脚 P22 &#xff0c;P23&#xff0c;P24 P22 、P23、P24 连接 3-8 译码器 三输入、8输出 8 输出 &#xff0c;连接8个LED1~LED8 用到三个芯片&#xff…

MATLAB 2023安装方法之删除旧版本MATLAB,安装新版本MATLAB

说明&#xff1a;之前一直使用的是MATLAB R2020b&#xff0c;但最近复现Github上的程序时&#xff0c;运行不了&#xff0c;联系作者说他的程序只能在MATLAB 2021之后的版本运行&#xff0c;因此决定安装最新版本的MATLAB。 系统&#xff1a;Windows 11 需要卸载的旧MATLAB 版…

redis面试题二

redis如何处理已过期的元素 常见的过期策略 定时删除&#xff1a;给每个键值设置一个定时删除的事件&#xff0c;比如有一个key值今天5点过期&#xff0c;那么设置一个事件5点钟去执行&#xff0c;把它数据给删除掉&#xff08;优点&#xff1a;可以及时利用内存及时清除无效数…

Mac版JFormDesigner IDEA插件安装(非商业用途)

前言 仅供个人开发者使用&#xff0c;勿用作商业用途。 仅供个人开发者使用&#xff0c;勿用作商业用途。 仅供个人开发者使用&#xff0c;勿用作商业用途。 感觉做了这些年开发&#xff0c;怎么感觉市场越搞越回去了。桌面应用又成主流了&#xff1f; 甲方让做桌面客户端&am…

Java String类(2)

String方法 字符串拆分 可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串 相关方法如下&#xff1a; 方法功能String[ ] split(String regex)//以regex分割将字符串根据regex全部拆分String[ ] split(String regex, int limit)将字符串以指定的格式&#xff0c;拆…

Liquid UI和Fiori的区别

主要围绕以下几个方面就Liquid UI和Firor来进行比较&#xff1a; 开发周期开发成本稳定性和支援性平台架构 影响Firor决策的因素&#xff1a; 复杂的编程过程&#xff0c;Fiori对开发人员要求高&#xff0c;开发难度大&#xff0c;而Liquid UI让开发人员不需要懂SAP后端&…

jdk-8u371-linux-x64.tar.gz jdk-8u371-windows-x64.exe 【jdk-8u371】 全平台下载

jdk-8u371 全平台下载 jdk-8u371-windows-x64.exejdk-8u371-linux-x64.rpmjdk-8u371-linux-x64.tar.gzjdk-8u371-macosx-x64.dmgjdk-8u371-linux-aarch64.tar.gz 下载地址 迅雷云盘 链接&#xff1a;https://pan.xunlei.com/s/VNdLL3FtCnh45nIBHulh_MDjA1?pwdw4s6 百度…

无涯教程-JavaScript - TDIST函数

The TDIST function replaces the T.DIST.2T & T.DIST.RT functions in Excel 2010. 描述 该函数返回学生t分布的百分点(概率)​​,其中数值(x)是t的计算值,将为其计算百分点。 t分布用于小样本数据集的假设检验。使用此函数代替t分布的临界值表。 语法 TDIST(x,deg_fr…

Elasticsearch:利用矢量搜索进行音乐信息检索

作者&#xff1a;Alex Salgado 欢迎来到音乐信息检索的未来&#xff0c;机器学习、矢量数据库和音频数据分析融合在一起&#xff0c;带来令人兴奋的新可能性&#xff01; 如果你对音乐数据分析领域感兴趣&#xff0c;或者只是热衷于技术如何彻底改变音乐行业&#xff0c;那么本…

[管理与领导-67]:IT基层管理者 - 辅助技能 - 4- 职业发展规划 - 评估你与公司的八字是否相合

目录 前言&#xff1a; 一、概述 二、八字相合的步骤 2.1 企业文化是否相合 2.2.1 企业文化对职业选择的意义 2.2.2 个人与企业三观不合的结果 2.2.3 什么样的企业文化的公司不能加入 2.2 公司的发展前景 2.3 公司所处行业发展 2.4 创始人的三观 2.5 创始人与上司的…

docker安装grafana,prometheus,exporter以及springboot整合详细教程(GPE)

springboot项目ip:192.168.168.1 测试服务器ip:192.168.168.81 文章来自互联网,自己略微整理下,更容易上手,方便自己,方便大家 最终效果: node springboot 1.下载镜像 docker pull prom/node-exporter docker pull prom/mysqld-exporter docker pull google/cadvisor dock…