Qt QProcess进程间调用及交互通信,完整示例

news2024/12/29 9:41:33

1. 概述

使用Qt进行应用程序开发,主要是通过QProcess类用于启动外部程序并与其进行通信.

1.1. 运行进程

要启动进程,需要运行的程序的名称和命令行参数作为参数传递给start()。参数以QStringList形式提供。
start()方法原型:

void start(const QString &program, const QStringList &arguments, OpenMode mode = ReadWrite)
void start(const QString &command, OpenMode mode = ReadWrite)

或者,也可以使用setProgram()setArguments()设置要运行的程序,然后调用start()open()
以下是setProgram()setArguments()open()函数原型:

// 以何种方式打开
    bool open(OpenMode mode = ReadWrite) Q_DECL_OVERRIDE;
// 获取program
QString program() const;
// 设置program
    void setProgram(const QString &program);
// 获取参数
QStringList arguments() const;
// 设置参数,参数以QStringList形式传递
    void setArguments(const QStringList & arguments);

例如,以下代码片段在X11平台上通过将包含“-style”和“fusion”的字符串作为参数列表中的两个项来以Fusion样式运行模拟时钟示例:

      QObject *parent;
      ...
      QString program = "./path/to/Qt/examples/widgets/analogclock";
      QStringList arguments;
      arguments << "-style" << "fusion";

      QProcess *myProcess = new QProcess(parent);
      myProcess->start(program, arguments);

然后,QProcess进入启动状态,并在程序启动时进入运行状态并发出started()信号。
QProcess允许将进程视为顺序I/O设备。因此可以像使用QTcpSocket访问网络连接一样写入和读取进程。然后,通过调用write()写入进程的标准输入,并通过调用read()readLine()getChar()读取标准输出。由于继承了QIODeviceQProcess也可以作为QXmlReader的输入源,或者用于生成要使用QNetworkAccessManager上传的数据。
当进程退出时,QProcess将重新进入NotRunning(初始状态),并发出finished()信号。
finished()信号以进程的退出码退出状态作为参数提供,还可以调用exitCode()获取最后完成的进程的退出码,以及exitStatus()获取其退出状态。如果在任何时间点发生错误,QProcess将发出errorOccurred()信号。还可以调用error()查找上次发生的错误类型,并调用state()查找当前进程状态。
注意:QProcess不支持VxWorksiOStvOSwatchOS通用Windows平台

1.2. 通过通道进行通信

进程具有两个预定义的输出通道:标准输出通道(stdout)提供常规控制台输出,标准错误通道(stderr)通常提供进程打印的错误。这些通道代表了两个独立的数据流。
可以通过调用setReadChannel()在它们之间切换。
当当前读取通道上有数据可用时,QProcess发出readyRead()信号。当有新的标准输出数据可用时,它还会发出readyReadStandardOutput(),当有新的标准错误数据可用时,会发出readyReadStandardError()。之后可以通过调用readAllStandardOutput()readAllStandardError()显式地从两个通道中读取所有数据,可以不再调用read()readLine()getChar()
通道可以理解为对象交互之间的看得见或看不见的某种联系。请注意,进程的输出通道对应于QProcess的读通道,而进程的输入通道对应于QProcess的写通道。这是因为我们使用QProcess读取的是进程的输出,我们写入的是进程的输入。
QProcess可以合并两个输出通道,使运行进程的标准输出和标准错误数据都使用标准输出通道。在启动进程之前调用setProcessChannelMode()并传递MergedChannels作为参数来激活此功能。还可以选择将运行进程的输出转发给调用主进程,通过传递ForwardedChannels作为参数。也可以仅转发其中一个输出通道 - 通常会使用ForwardedErrorChannel,但也存在ForwardedOutputChannel
请注意,在GUI应用程序中使用通道转发通常是一个不好的主意 - 应该以图形方式呈现错误。
void QProcess::setProcessChannelMode(ProcessChannelMode) 用法:
QProcess标准输出和标准错误通道的通道模式设置为指定的模式。此模式将在下次调用start()时使用。例如:

QProcess builder;
  builder.setProcessChannelMode(QProcess::MergedChannels);
  builder.start("make", QStringList() << "-j2");

  if (!builder.waitForFinished())
      qDebug() << "Make failed:" << builder.errorString();
  else
      qDebug() << "Make output:" << builder.readAll();

某些进程需要特殊的环境设置才能运行。可以通过调用setProcessEnvironment()为进程设置环境变量。要设置工作目录,请调用setWorkingDirectory()。默认情况下,进程在调用进程的当前工作目录中运行。
void QProcess::setProcessEnvironment(const QProcessEnvironment &environment)用法:
设置QProcess将传递给子进程的环境。
例如,下面的代码添加了环境变量TMPDIR:

  QProcess process;
  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
  env.insert("TMPDIR", "C:\\MyApp\\temp"); // Add an environment variable
  process.setProcessEnvironment(env);
  process.start("myapp");

注意:在QNX上,设置工作目录可能会导致除QProcess调用线程之外的所有应用程序线程在生成过程中暂时冻结,这是由于操作系统的限制。

2. 常用方法

2.1. 公共函数

  • QStringList arguments() const:获取进程的参数列表。
  • void closeReadChannel(ProcessChannel channel):关闭指定的读通道。
  • void closeWriteChannel():关闭写通道。
  • CreateProcessArgumentModifier createProcessArgumentsModifier() const:获取创建进程参数修改器。
  • QProcess::ProcessError error() const:获取进程的错误状态。
  • int exitCode() const:获取进程的退出码。
  • QProcess::ExitStatus exitStatus() const:获取进程的退出状态。
  • InputChannelMode inputChannelMode() const:获取输入通道的模式。
  • QString nativeArguments() const:获取原生参数。
  • ProcessChannelMode processChannelMode() const:获取进程通道的模式。
  • QProcessEnvironment processEnvironment() const:获取进程的环境变量。
  • qint64 processId() const:获取进程的ID。
  • QString program() const:获取程序的路径。
  • QByteArray readAllStandardError():读取并返回所有标准错误输出。
  • QByteArray readAllStandardOutput():读取并返回所有标准输出。
  • ProcessChannel readChannel() const:获取当前读取通道。
  • void setArguments(const QStringList &arguments):设置进程的参数列表。
  • void setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier):设置创建进程参数修改器。
  • void setInputChannelMode(InputChannelMode mode):设置输入通道的模式。
  • void setNativeArguments(const QString &arguments):设置原生参数。
  • void setProcessChannelMode(ProcessChannelMode mode):设置进程通道的模式。
  • void setProcessEnvironment(const QProcessEnvironment &environment):设置进程的环境变量。
  • void setProgram(const QString &program):设置程序的路径。
  • void setReadChannel(ProcessChannel channel):设置当前的读取通道。
  • void setStandardErrorFile(const QString &fileName, OpenMode mode = Truncate):将标准错误输出重定向到指定文件。
  • void setStandardInputFile(const QString &fileName):将标准输入重定向到指定文件。
  • void setStandardOutputFile(const QString &fileName, OpenMode mode = Truncate):将标准输出重定向到指定文件。
  • void setStandardOutputProcess(QProcess *destination):将标准输出重定向到另一个进程。
  • void setWorkingDirectory(const QString &dir):设置工作目录。
  • void start(const QString &program, const QStringList &arguments, OpenMode mode = ReadWrite):启动指定的程序。
  • void start(const QString &command, OpenMode mode = ReadWrite):启动指定的命令。
  • void start(OpenMode mode = ReadWrite):启动进程。
  • QProcess::ProcessState state() const:获取进程的状态。
  • bool waitForFinished(int msecs = 30000):等待进程完成,最多等待指定的毫秒数。
  • bool waitForStarted(int msecs = 30000):等待进程启动,最多等待指定的毫秒数。
  • QString workingDirectory() const:获取工作目录。

2.2. 信号

  • void errorOccurred(QProcess::ProcessError error):当进程发生错误时触发。
  • void finished(int exitCode, QProcess::ExitStatus exitStatus):当进程结束时触发。
  • void readyReadStandardError():当标准错误输出有可读数据时触发。
  • void readyReadStandardOutput():当标准输出有可读数据时触发。
  • void started():当进程开始时触发。
  • void stateChanged(QProcess::ProcessState newState):当进程状态发生变化时触发。

##2.3. 静态公共成员

  • int execute(const QString &program, const QStringList &arguments):执行指定的程序。
  • int execute(const QString &command):执行指定的命令。
  • QString nullDevice():获取空设备的路径。
  • bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(), qint64 *pid = Q_NULLPTR):以分离模式启动指定的程序。
  • bool startDetached(const QString &command):以分离模式启动指定的命令。
  • QStringList systemEnvironment():获取系统的环境变量。

3. 示例之调用进程

调用进程实现相对简单。
首先是调用端,先创建一个UI,如下:
image.png
在头文件里添加:

QProcess*        m_pProcess = nullptr;

然后在“调用客户端”槽函数内,添加:

    if(!m_pProcess)
    {
        m_pProcess = new QProcess(this);
        // 完成时调用
        connect(m_pProcess, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus){
            Q_UNUSED(exitCode)
            Q_UNUSED(exitStatus)
        });

        // 进程错误时触发
        connect(m_pProcess, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), this, [=](QProcess::ProcessError error1){
            Q_UNUSED(error1)
        });

        // 读取
        connect(m_pProcess, &QProcess::readyRead, this, [this](){
            if(!m_pProcess)
                return;
            QString strOutput = QString("[客户端发送输出 ] %1").arg(QString(m_pProcess->readAllStandardOutput()));
            ui->textBrowser->append(strOutput);
        });
        // 读取标准错误信息
        connect(m_pProcess, &QProcess::readyReadStandardError, this, [=](){
            QString strError = QString("[客户端发送错误 ] %1").arg(QString(m_pProcess->readAllStandardError()));
            ui->textBrowser->append(strError);
        });
        // 状态改变时触发
        connect(m_pProcess, &QProcess::stateChanged, this, [=](QProcess::ProcessState state){
            Q_UNUSED(state)
        });

    }
// 启动进程    m_pProcess->start("C:/Users/Desktop/process.exe");

然后是被调用的进程端:
UI:
image.png

启动后,显示如下;
点击“调用客户端”
image.png

4. 进程间的通信

进程间的通信,当通过进程调用后,调用端如下方代码所示,通过绑定readyReadreadyReadStandardError可以获取输出和错误

        // 读取
        connect(m_pProcess, &QProcess::readyRead, this, [this](){
            if(!m_pProcess)
                return;
            QString strOutput = QString("[客户端发送输出 ] %1").arg(QString(m_pProcess->readAllStandardOutput()));
            ui->textBrowser->append(strOutput);
        });
        // 读取标准错误信息
        connect(m_pProcess, &QProcess::readyReadStandardError, this, [=](){
            QString strError = QString("[客户端发送错误 ] %1").arg(QString(m_pProcess->readAllStandardError()));
            ui->textBrowser->append(strError);
        });

但调用端发送信息后,被调用端需要处理接收到的数据。
调用端,在构造里,启动一个线程

QtConcurrent::run(this, &MainWindow::readstdin);
void MainWindow::readstdin()
{
    bool ok = true;
    char chBuf[4096];
    DWORD dwRead;
    HANDLE hStdinDup;

    const HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
    if (hStdin == INVALID_HANDLE_VALUE)
        return;

    DuplicateHandle(GetCurrentProcess(), hStdin,
                    GetCurrentProcess(), &hStdinDup,
                    0, false, DUPLICATE_SAME_ACCESS);

    CloseHandle(hStdin);
    while (ok) {
        ok = ReadFile(hStdinDup, chBuf, sizeof(chBuf), &dwRead, NULL);
        // emit sig_log(QLatin1String("ok is:")+QString::number(ok));
        if (ok && dwRead != 0)
        {
            emit sig_receivedCommand(QString::fromUtf8(chBuf, dwRead));
        }
    }
}

以上代码作用:
从一个标准输入流读取数据,并将其转换为QString对象,然后通过一个信号(sig_receivedCommand)发送出去。

  1. bool ok = true;
    • 定义一个布尔变量ok并初始化为true。这个变量用于检查是否成功地从标准输入读取了数据。
  2. char chBuf[4096];
    • 定义一个字符数组chBuf,大小为4096字节。这个数组用于存储从标准输入读取的数据。
  3. DWORD dwRead;
    • 定义一个DWORD类型的变量dwRead,用于存储实际读取的字节数。
  4. HANDLE hStdinDup;
    • 定义一个句柄变量hStdinDup,用于存储标准输入的副本的句柄。
  5. const HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
    • 获取标准输入的句柄,并将其存储在变量hStdin中。
  6. if (hStdin == INVALID_HANDLE_VALUE) return;
    • 检查是否成功获取了标准输入的句柄。如果没有,则直接返回。
  7. DuplicateHandle(GetCurrentProcess(), hStdin, GetCurrentProcess(), &hStdinDup, 0, false, DUPLICATE_SAME_ACCESS);
    • 创建一个标准输入句柄的副本,并将其存储在变量hStdinDup中。这样做的目的是为了在关闭原始句柄后仍然能够读取数据。
  8. CloseHandle(hStdin);
    • 关闭原始的标准输入句柄。现在只有副本句柄hStdinDup是打开的。
  9. while (ok) { ... }
    • 一个无限循环,持续读取标准输入的数据,直到读取失败。
  10. ok = ReadFile(hStdinDup, chBuf, sizeof(chBuf), &dwRead, NULL);
    • 从标准输入的副本中读取数据到chBuf数组中。读取的字节数存储在dwRead中,并更新ok变量的状态。
  11. if (ok && dwRead != 0) { ... }
    • 检查是否成功读取了数据,并且实际读取的字节数不为0。如果满足这两个条件,则执行花括号中的代码。
  12. emit sig_receivedCommand(QString::fromUtf8(chBuf, dwRead));
  • 将读取的数据(存储在chBuf中)转换为QString对象,并通过信号(sig_receivedCommand)发送出去。这里假设程序使用了Qt框架。
  1. }
  • 结束while循环。如果读取失败,循环将终止。

结果如下所示:
image.png

5. 进程间的通信之完整代码链接

完整示例、具体代码链接: https://download.csdn.net/download/MrHHHHHH/88719913?spm=1001.2014.3001.5501

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】HP-Socket(二):框架介绍、功能说明

1、接口 1.1 接口模型 1.2 三类接口 HP-Socket 定义了三类接口 组件接口&#xff08;如&#xff1a;ITcpServer / IUdpClient&#xff09;&#xff1a;声明组件操作方法&#xff0c;应用程序创建组件对象后通过该接口来使用组件组件实现类&#xff08;如&#xff1a;CTcpSer…

小巧且兼具高性能的小模型 TinyLlama 等

TinyLlama-1.1B 小模型在边缘设备上有着广泛的应用&#xff0c;如智能手机、物联网设备和嵌入式系统&#xff0c;这些边缘设备通常具有有限的计算能力和存储空间&#xff0c;它们无法有效地运行大型语言模型。因此&#xff0c;深入探究小型模型显得尤为重要。 来自新加坡科技…

springboot虹软人脸识别集成

准备工作 虹软开放平台中创建一个新的应用 虹软开发平台【点我跳转】 开始上代码 基本配置 将下载的jar包放到src同级目录下 <!-- 虹软--><dependency><groupId>com.arcsoft.face</groupId><artifactId>arcsoft-sdk-face</artifactI…

【RH850U2A芯片】RAM and Flash介绍

目录 前言 正文 1.RH850-U2A16芯片RAM 1.1 用户使用RAM类型及大小 1.2 各类RAM起始地址 1.3 LRAM和CRAM的区别 1.4 RAM初始化问题 1.5 RAM使用经验 2.RH850-U2A16芯片Flash 2.1 Flash类型及大小 2.2 各类Flash的起始地址 2.3 Code Flash和Data Flash的区别 2.4 Fl…

谷粒商城项目|微服务架构的一些与思考解决跨域问题

1.微服务架构的组成每部分的作用 2.还有其他的微服务架构模式吗 3.微服务服务交互的方式 1&#xff09;grpc 2&#xff09;rest api 4.微服务网关与API网关&#xff1f; 5.注册中心比较&#xff08;Nacos与Eureka&#xff09; Nacos Nacos 是阿里巴巴开源的项目&#xff0c;N…

Vue2.v-指令

v-if 在双引号中写判断条件。 <div v-if"score>90">A</div> <div v-else-if"score>80">B</div> <div v-else>C</div>v-on: :冒号后面跟着事件。 为了简化&#xff0c;可以直接用代替v-on:。 事件名“内联语…

Nessus漏洞扫描工具安装、使用技巧及注意事项

Nessus是一款功能强大的安全评估工具&#xff0c;它可以帮助安全团队快速发现网络中潜在的安全风险和漏洞&#xff0c;并对其进行评估和修复。对于渗透测试人员来说&#xff0c;Nessus更是必不可少的工具之一。 1. Nessus安装 获取安装包&#xff0c;官网地址&#xff1a;http…

【数据库】MySQL锁

一、锁的基本概念 1、锁的定义 锁是协调多个进程或线程并发访问数据库资源的一种机制。 MySQL中的锁是在服务器层或者存储引擎层实现的&#xff0c;保证了数据访问的一致性与有效性。但加锁是消耗资源的&#xff0c;锁的各种操作&#xff0c;包括获得锁、检测锁是否已解除、…

26 数字验证

效果演示 实现了一个简单的数字密码输入表单&#xff0c;用户需要输入一个4位数字密码来验证身份。表单包含一个标题、描述、输入字段、两个按钮和一个关闭按钮。输入字段是一个4位数字密码&#xff0c;用户需要在每个输入框中输入数字来输入密码。两个按钮分别是“验证”和“清…

简单的MOV转MP4方法

1.下载腾讯的QQ影音播放器, 此播放器为绿色视频播放器, 除了播放下载好的视频外没有臃肿无用功能 官网 QQ影音 百度网盘链接&#xff1a;https://pan.baidu.com/s/1G0kSC-844FtRfqGnIoMALA 提取码&#xff1a;dh4w 2.用QQ影音打开MOV文件 3.右下角打开影音工具箱 , 选择截取…

【Java并发】聊聊concurrentHashMap的put核心流程

结构介绍 1.8中concurrentHashMap采用数组链表红黑树的方式存储&#xff0c;并且采用CASSYN的方式。在1.7中主要采用的是数组链表&#xff0c;segment分段锁reentrantlock。本篇主要在1.8基础上介绍下. 那么&#xff0c;我们的主要重点是分析什么呢&#xff0c;其实主要就是p…

强化学习在生成式预训练语言模型中的研究现状简单调研

1. 绪论 本文旨在深入探讨强化学习在生成式预训练语言模型中的应用&#xff0c;特别是在对齐优化、提示词优化和经验记忆增强提示词等方面的具体实践。通过对现有研究的综述&#xff0c;我们将揭示强化学习在提高生成式语言模型性能和人类对话交互的关键作用。虽然这些应用展示…

kubernetes volume 数据存储详解

写在前面&#xff1a;如有问题&#xff0c;以你为准&#xff0c; 目前24年应届生&#xff0c;各位大佬轻喷&#xff0c;部分资料与图片来自网络 内容较长&#xff0c;页面右上角目录方便跳转 概述 容器的生命周期可能很短&#xff0c;会被频繁的创建和销毁 保存在容器中的…

Leetcode刷题笔记题解(C++):无重复字符的最长子串

思路&#xff1a; 利用滑动窗口的思想&#xff0c;用起始位置startindex和curlength来记录这个滑动窗口的大小&#xff0c;并且得出最长距离&#xff1b;利用哈希表来判断在滑动窗口中是否存在重复字符&#xff0c;代码如下所示&#xff1a; class Solution { public:int len…

6.1 截图工具HyperSnap6简介

图片是组成多媒体作品的基本元素之一&#xff0c;利用图片可以增强多媒体作品的亲和力和说说服力。截取图片最简单的方法是直接按下键盘上的“PrintScreen”键截取整个屏幕或按下“AltPrintScreen”组合键截取当前活动窗口&#xff0c;然后在画笔或者其它的图片处理软件中进行剪…

基于SSM的在线电影票购买系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的在线电影票购买系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring…

【模拟IC学习笔记】Cascode OTA 设计

辅助定理 增益Gm*输出阻抗 输出短路求Gm 输入置0求输出阻抗 求源极负反馈的增益 随着Vin的增加&#xff0c;Id也在增加&#xff0c;Rs上压降增加&#xff0c;所以&#xff0c;Vin的一部分电压体现在Rs上&#xff0c;而不是全部作为Vgs&#xff0c;因此导致Id变得平滑。 Rs足…

软件测试|MySQL DISTINCT关键字过滤重复数据

简介 在MySQL中&#xff0c;有时候我们需要从表中检索唯一的、不重复的数据。这时&#xff0c;我们可以使用DISTINCT关键字来过滤掉重复的数据行。在本文中&#xff0c;我们将深入探讨MySQL中DISTINCT的用法以及如何在查询中使用它来得到不重复的结果集。 基本语法 DISTINCT…

Influxdb2修改管理员密码

通过恢复管理员令牌来重置InfluxDB2管理员的密码 1.找到数据库的配置文件 一般为config.json 2.配置文件的的blod文件配置 3.在这个混合文本和二进制json文件中搜索已知的用户名或token之类的字符串。 例如&#xff1a; "id":"0bd73badf2941000","…

系列十四、理解MySQL varchar(50)

一、理解MySQL varchar(50) 1.1、概述 日常开发中&#xff0c;数据库建表是必不可少的一个环节&#xff0c;建表的时候通常会看到设定某个字段的长度为varchar(50)&#xff0c;例如如下建表语句&#xff1a; 那么怎么理解varchar(50)&#xff1f;这个分情况的&#xff0c;MySQ…