Qt QProcess 进程间通信读写数据通信

news2025/1/11 3:49:01

本文介绍了如何使用Qt的QProcess  进行程序开发,包括启动进程间通信、设置环境变量、通用方法;方便在日常开发中使用;

1.使用Qt进行程序开发,可以通过QProcess类用于启动外部程序并与其进行通信.;

进程A(例如主程序)创建了一个QProcess B,这个B就称为A的子进程,而A称为B的父进程。

1.1. 运行进程 

可以使用 Start  or Open

要启动进程,需要运行的程序的名称和命令行参数作为参数传递给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;

QString program() const;

 void setProgram(const QString &program);

QStringList arguments() const;

 void setArguments(const QStringList & arguments);

1.2 环境运行设置

因为有一些程序会有依赖,所以需要设备运行环境:

通过调用setProcessEnvironment()为进程设置环境变量。

要设置工作目录,请调用setWorkingDirectory()。默认情况下,进程在调用进程的当前工作目录中运行

原型:

void QProcess::setProcessEnvironment(const QProcessEnvironment &environment)

样例:

  QProcess process;
  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
  env.insert("PATH", "E:\\Program"); // Add an environment variable
  process.setProcessEnvironment(env);
  process.start("app.exe");

1.3. 进程间通信
1.3.1关于父进程读写子进程的数据,主要是用到

子进程接收到了父进程数据,两个信号会发射出来:
void readyReadStandardError()
void readyReadStandardOutput()

父进程通过上面这两个信号,判断读取子进程发来的消息;

QByteArray QProcess::readAllStandardError()
QByteArray QProcess::readAllStandardOutput()

QProcess::write()发出信息

1.3.2 关于子进程读写父进程的数据,主要是用到

Windows中:需要开启一个线程来管理stdin的文件变化,这个需要使用Windows API函数
linux中:使用QSocketNotifier 监听 stdin文件,当改文件有变化是,读取信息

 

ReadFile(hStdinDup,chbuf,sizeof(chbuf),&dwRead,NULL);// get  hstdinDup handle data

这个是阻塞函数,类似控制台程序中的cin >> data,或者gets()。

因此需要开启一个线程来管理stdin的文件变化(函数中有涉及到while阻塞,一直检测标准输入通道stdin是否有可读取的信息,因此另开线程),在pro文件中添加:QT +=concurrent。实例代码如下:

QFuture<void> fu=QtConcurrent::run(this,&Widget::readStdin);// open a thread

void Widget::readStdin()
{
    bool ok=true;
    char chbuf[1024]; 
    DWORD dwRead; 
    HANDLE hStdinDup;//HANDLE  
 
    const HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);//GetStdHandle 
    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));
        }
    }
 
}


 linux平台:QFile来读取标准输入

QProcess子进程通过QFile来读取标准输入来接收父进程信息。通过QFile绑定QSocketNotifier来接收标准输入的实时信号,因为QSocketNotifier的activated信号可以通过标准输入是否有消息实时触发。

QProcess子进程通过QFile绑定标准输出stdout来发送消息给父进程。
注意:子进程读取信息不能通过QFile的readline等接口读取父进程信息,因为QFile他会读取标准输入的所有信息,并且不到长度就没有返回
 

m_file.open(stdin, QFile::ReadOnly); //stdin=0
     if (m_file.isOpen())
     {
         m_clientsocket = new QSocketNotifier(m_file.handle(), QSocketNotifier::Read,this);
         connect(m_clientsocket,SIGNAL(activated(int)),this,SLOT(slotreaddata(int)));
     }void MainWindow::slotreaddata(int fd)
 {
     if(fd != m_file.handle() )
     return;    char buf[128] = {0};
     read(fd,buf,sizeof(buf));      
     m_readedit->append(QString::fromUtf8("rev msg:%1").arg(buf));
}

2. 程序样例:

主进程
 

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    if(m_pProcess)
    {
        m_pProcess->close();
    }
    delete ui;
}

void MainWindow::on_btn_invokingClient_clicked()
{
    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("G:/workspace/Qt_process-invoke-client/build-client-Desktop_Qt_5_12_4_MSVC2017_64bit-Debug/debug/client.exe");
}

void MainWindow::on_btn_sendValueToClient_clicked()
{
    if(!m_pProcess)
        return;
    // 可输中文
    m_pProcess->write(ui->lineEdit->text().toUtf8());
}

子进程:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>
#include <QFile>
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <QFuture>
#include <QtConcurrent/QtConcurrent>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle("client");

    QFuture<void> f1 = QtConcurrent::run(this, &MainWindow::readstdin);
    connect(this,&MainWindow::sig_receivedCommand, this, [&](QString text){
        ui->textBrowser->append("[读取标准输入 ] "+ text);
    });
    connect(this, &MainWindow::sig_log, this, &MainWindow::slot_print);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_btn_sendOutputToInvoker_clicked()
{
    QString text = ui->lineEdit->text();
    if(text.isEmpty()) return;
#if 0
    QFile fileout;
    if(fileout.open(stdout,QIODevice::WriteOnly)){
        fileout.write(text.toStdString().c_str());
    }else{
        printErr("open fail");
    }
    fileout.close();
#else
    std::cout << text.toStdString() << std::endl;
#endif
}

void MainWindow::printErr(const QString &errText)
{
    QFile fileerr;
    if(fileerr.open(stderr,QIODevice::WriteOnly)){
        fileerr.write(errText.toStdString().c_str());
    }
    fileerr.close();
}

void MainWindow::on_btn_sendErrToInvoker_clicked()
{
    QString text = ui->lineEdit->text();
    if(text.isEmpty()) return;
#if 1
    QFile fileerr;
    if(fileerr.open(stderr,QIODevice::WriteOnly)){
        fileerr.write(text.toStdString().c_str());
    }
    fileerr.close();
#else
    std::cerr << text.toStdString() << std::endl;
#endif
}

void MainWindow::slot_print(const QString &text)
{
    ui->textBrowser->append("[读取标准输入 ] "+ text);
}
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));
        }
    }
}

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

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

相关文章

【时时三省】tessy 集成测试:小白入门指导手册

目录 1,创建集成测试模块且分析源文件 2,设置测试环境 3,TIE界面设置相关函数 4,SCE界面增加用例 5,编辑数据 6,用例所对应的测试函数序列 7,添加 work task 函数 8,为测试场景添加函数 9,为函数赋值 10,编辑时间序列的数值 11,执行用例 12,其他注意事项…

Hadoop3:MR程序的数据倾斜问题处理

一、数据倾斜 什么是数据倾斜&#xff1f; 学过Redis集群的都知道数据倾斜这个问题。 就是大量数据&#xff0c;分配不均匀的现象。 二、MR数据倾斜 1、怎么判断出现数据倾斜&#xff1f; 数据频率倾斜——某一个区域的数据量要远远大于其他区域。 数据大小倾斜——部分记…

【STM32】RTT-Studio中HAL库开发教程四:DAC+DMA输出波形

文章目录 一、DAC介绍二、HAL库配置初始化三、RTT中初始化四、测试验证 一、DAC介绍 1.DAC作用 DAC&#xff08;Digital-to-Analog Converter&#xff09;&#xff0c;即为数字/模拟转换模块&#xff0c;又称D/A转换器&#xff1b;作用就是把输入的数字编码&#xff0c;转换成…

昇思25天学习打卡营第16天 | Vision Transformer图像分类

昇思25天学习打卡营第16天 | Vision Transformer图像分类 文章目录 昇思25天学习打卡营第16天 | Vision Transformer图像分类Vision Transform&#xff08;ViT&#xff09;模型TransformerAttention模块Encoder模块 ViT模型输入 模型构建Multi-Head Attention模块Encoder模块Pa…

Java对象转换为JSON字符串

0 写在前面 业务中有很多场景需要 把一个带有数据的 Java对象/Java集合转换为JSON 存入数据库中。 在需要的时候还需要吧和这个JSON字符串拿出来再次转换成Java对象/集合 1 Java对象与JSON字符串互转 引入依赖: <dependency><groupId>com.alibaba</groupId&…

解决VMware虚拟机在桥接模式下无法上网的问题

解决VMware虚拟机在桥接模式下无法上网的问题 windows11系统自动启动了热点功能&#xff0c;开启热点可能会干扰虚拟机的桥接设置。 方法一&#xff1a;windows11可以提供网络热点服务 方法二&#xff1a;手动指定桥接的物理网卡 方法一&#xff1a;关闭热点功能 优点&#xff…

【Java项目笔记】01项目介绍

一、技术框架 1.后端服务 Spring Boot为主体框架 Spring MVC为Web框架 MyBatis、MyBatis Plus为持久层框架&#xff0c;负责数据库的读写 阿里云短信服务 2.存储服务 MySql redis缓存数据 MinIO为对象存储&#xff0c;存储非结构化数据&#xff08;图片、视频、音频&a…

【开发指南】HTML和JS编写多用户VR应用程序的框架

1.概述 Networked-Aframe 的工作原理是将实体及其组件同步到连接的用户。要连接到房间&#xff0c;您需要将networked-scene组件添加到a-scene元素。对于要同步的实体&#xff0c;请向其添加networked组件。默认情况下&#xff0c;position和rotation组件是同步的&#xff0c;…

【Spring Cloud】掌握Gateway核心技术,实现高效路由与转发

目录 前言示例创建一个服务提供者创建网关 创建common子项目 前言 Spring Cloud Gateway 是一个基于 Spring Boot 的非阻塞 API 网关服务&#xff0c;它提供了动态路由、请求断言、过滤器等功能。 以下是关于 Spring Cloud Gateway 的示例&#xff1a; 示例 创建一个服务提…

什么是 std::ios::sync_with_stdio(false)

介绍 std::ios::sync_with_stdio(false) 是 C 中的一个配置设置&#xff0c;用于控制标准 I/O 流&#xff08;如 std::cin, std::cout&#xff09;的行为。这个设置主要用于优化输入输出操作的性能&#xff0c;尤其是在处理大量数据时。 在 C 中&#xff0c;标准流库&#xf…

PHP连接MySQL数据库

PHP本身不具备操作MySQL数据库的能力&#xff0c;需要借助MySQL扩展来实现。 1、PHP加载MySQL扩展&#xff1a;php.ini文件中。&#xff08;不要用记事本打开&#xff09; 2、PHP中所有扩展都是在ext的文件夹中&#xff0c;需要指定扩展所在路径&#xff1a;extension_dir。 3、…

3D问界—MAYA制作铁丝栅栏(透明贴图法)

当然&#xff0c;如果想通过建立模型法来实现铁丝栅栏的效果&#xff0c;也不是不行&#xff0c;可以找一下栅栏建模教程。本篇文章主要是记录一下如何使用透明贴图来实现创建铁丝栅栏&#xff0c;主要应用于场景建模&#xff0c;比如游戏场景、建筑场景等大环境&#xff0c;不…

Spring3(代理模式 Spring1案例补充 Aop 面试题)

目录 一、代理模式 介绍 意图 主要解决的问题 使用场景 实现方式 关键代码 应用实例 优点 缺点 使用建议 注意事项 结构 什么是代理模式&#xff1f; 为什么要用代理模式&#xff1f; 有哪几种代理模式&#xff1f; 1. 静态代理 实现 2. 基于接口的动态代理…

基于python旅游景点满意度分析设计与实现

1.1研究背景与意义 1.1.1研究背景 随着旅游业的快速发展&#xff0c;满意度分析成为评估旅游景点质量和提升游客体验的重要手段。海口市作为中国的旅游城市之一&#xff0c;其旅游景点吸引了大量游客。然而&#xff0c;如何科学评估和提升海口市旅游景点的满意度&#xff0c;…

Qt创建列表,通过外部按钮控制列表的选中下移、上移以及左侧图标的显现

引言 项目中需要使用列表QListWidget,但是不能直接拿来使用。需要创建一个列表,通过向上和向下的按钮来向上或者向下移动选中列表项,当当前项背选中再去点击确认按钮,会在列表项的前面出现一个图标。 实现效果 本实例实现的效果如下: 实现思路 思路一 直接采用QLis…

Spring Security之安全异常处理

前言 在我们的安全框架中&#xff0c;不管是什么框架&#xff08;包括通过过滤器自定义&#xff09;都需要处理涉及安全相关的异常&#xff0c;例如&#xff1a;登录失败要跳转到登录页&#xff0c;访问权限不足要返回页面亦或是json。接下来&#xff0c;我们就看看Spring Sec…

海外营销推广:快速创建维基百科(wiki)词条-大舍传媒

一、维基百科的永久留存问题 许多企业和个人关心维基百科是否能永久留存。实际上&#xff0c;只要企业和个人的行为没有引起维基百科管理方的反感&#xff0c;词条就可以长期保存。如果有恶意行为或被投诉&#xff0c;维基百科可能会对词条进行删除或修改。 二、创建维基百科…

为fooocus v2.5.0安装groundingdino

在win10下折就fooocus&#xff0c;使用git pull命令更新本地&#xff0c;然后…\python_embeded\python.exe -m pip install -r .\requirements_versions.txt更新依赖关系包。 卡在groundingdino的安装上&#xff0c;先在requirements_versions.txt中删除它&#xff0c;安装其他…

第十课:telnet(远程登入)

如何远程管理网络设备&#xff1f; 只要保证PC和路由器的ip是互通的&#xff0c;那么PC就可以远程管理路由器&#xff08;用telnet技术管理&#xff09;。 我们搭建一个下面这样的简单的拓扑图进行介绍 首先我们点击云&#xff0c;把云打开&#xff0c;点击增加 我们绑定vmn…

线程的中断和同步问题

1、自动终断【完成】&#xff1a;一个线程完成执行后&#xff08;即run方法执行完毕&#xff09;&#xff0c;不能再次运行 。 2、手动中断&#xff1a; stop( ) —— 已过时&#xff0c;基本不用。&#xff08;不安全&#xff0c;就像是突然停电&#xff09; interrupt( ) …