0


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

1. 概述

使用

Qt

进行应用程序开发,主要是通过

QProcess

类用于启动外部程序并与其进行通信.

1.1. 运行进程

要启动进程,需要运行的程序的名称和命令行参数作为参数传递给

start()

。参数以

QStringList

形式提供。

start()

方法原型:

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

或者,也可以使用

setProgram()

setArguments()

设置要运行的程序,然后调用

start()

open()


以下是

setProgram()

setArguments()

open()

函数原型:

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

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

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

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

然后,

QProcess

进入启动状态,并在程序启动时进入运行状态并发出

started()

信号。

QProcess

允许将进程视为顺序I/O设备。因此可以像使用

QTcpSocket

访问网络连接一样写入和读取进程。然后,通过调用

write()

写入进程的标准输入,并通过调用

read()

readLine()

getChar()

读取标准输出。由于继承了

QIODevice

QProcess

也可以作为

QXmlReader

的输入源,或者用于生成要使用

QNetworkAccessManager

上传的数据。
当进程退出时,

QProcess

将重新进入

NotRunning

(初始状态),并发出

finished()

信号。

finished()

信号以进程的

退出码

退出状态

作为参数提供,还可以调用

exitCode()

获取最后完成的进程的退出码,以及

exitStatus()

获取其退出状态。如果在任何时间点发生错误,

QProcess

将发出

errorOccurred()

信号。还可以调用

error()

查找上次发生的错误类型,并调用

state()

查找当前进程状态。
注意:

QProcess

不支持

VxWorks

iOS

tvOS

watchOS

通用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();elseqDebug()<<"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 =newQProcess(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. 进程间的通信

进程间的通信,当通过进程调用后,调用端如下方代码所示,通过绑定

readyRead

readyReadStandardError

可以获取输出和错误

// 读取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);
voidMainWindow::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

标签: qt 交互 开发语言

本文转载自: https://blog.csdn.net/MrHHHHHH/article/details/135490531
版权归原作者 FreeLikeTheWind. 所有, 如有侵权,请联系我们删除。

“Qt QProcess进程间调用及交互通信,完整示例”的评论:

还没有评论