草庐IT

关于Qt的QProcess进程间双向通信

weixin_46424582 2023-04-05 原文

文章目录


前言

Qprocess作为Qt的进程通信类,在程序中的应用还是挺多的,不管是启动一个命令行,还是另外启动一个辅助程序,QProcess都是不可或缺的。

之前也遇到过类似场景,主进程开始一个辅助进程执行Python脚本,需要传递函数名和参数,并且接受执行结果,那会是用的共享内存做的,当时是单向,主进程在共享内存段写入函数名和参数,副进程定时读取,有滞后。反正需求是实现了,当时也没想那么多。。。

最近有时间,专门研究了下QProcess,双向通信是可行的。当然我这边环境是基于windows的,Qt5.9+msvc2017 x64,系统是win10

一、QProceess简介

关于QProcess的介绍我就不多说了,相信大家都很了解了,不是很了解的可以查看Qt文档。我这里主要说下几个信号:


void readyReadStandardError()
void readyReadStandardOutput()

这两个对应的就是stdout和stderr,即副进程的标准输出和标准错误通道有可读内容是,这两个信号会发出来,主进程只要绑定这两个槽函数进行相应处理就行了。


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

这两个就是上面绑定的槽函数里面,读取对应的内容

二、实例

1.进程A(主进程)

代码如下(示例):

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

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow),mProcess(new QProcess)
{
    ui->setupUi(this);
    setWindowTitle("processServer");
    init_Process();
}

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

void MainWindow::init_Process()
{
    connect(mProcess,&QProcess::readyReadStandardOutput,this,&MainWindow::slot_readyStandandOutput);
    connect(mProcess,&QProcess::readyReadStandardError,this,[=](){
        QString log = mProcess->readAllStandardError();
        print_log(0,log);
    });
    QStringList argunments;
    argunments <<"123456";
    mProcess->start("F:/QtProject/build-processClient-Desktop_Qt_5_9_9_MSVC2017_64bit-Release/release/processClient.exe",argunments);
    if(mProcess->waitForStarted(3))
    {
        qDebug()<<"进程启动成功";
    }else{
        qDebug()<<"进程启动失败!";
    }
}

void MainWindow::print_log(quint8 t,  QString &log)
{
    if(t){
        log="[标准输出]:"+log;
        ui->plainTextEdit->appendHtml("<font color=\"#000000\">" + log + "</font> ");
    }else{
        log="[标准错误]:"+log;
        ui->plainTextEdit->appendHtml("<font color=\"#FF0000\">" + log + "</font> ");
    }
}

void MainWindow::slot_readyStandandOutput()
{
    QString log = mProcess->readAllStandardOutput();
    print_log(1,log);
}

void MainWindow::on_pushButton_clicked()
{
    QString text = ui->lineEdit->text();
    if(text.isEmpty()) return;
    if(mProcess){
        mProcess->write(text.toStdString().c_str());
    }
}

demo中构造函数里面进行初始化,开启副进程,路径记得换下你自己的路径,参数的话,传不传都行,根据自己需要。

2.进程B

代码如下(示例):

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <QFuture>
#include <QtConcurrent/QtConcurrent>

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

#if 0
    QTimer::singleShot(5000, this,[=](){initFileIN();});
#else
    QFuture<void> f1 = QtConcurrent::run(this,&MainWindow::readstdin);
    connect(this,&MainWindow::sig_receivedCommand,this,[&](QString text){
        ui->textEdit->append("[读取标准输入]"+ text);
    });
    connect(this,&MainWindow::sig_log,this,&MainWindow::slot_print);
#endif
}

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


void MainWindow::on_pushButton_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_pushButton_2_clicked()
{
    QString text = ui->lineEdit->text();
    if(text.isEmpty()) return;
#if 0
    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)
{
    qDebug()<<text;
    ui->textEdit->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));
    }
}

构造函数中开了个Qtconcuurrent高级线程接口,运行readstdin函数,函数中有涉及到while阻塞,一直检测标准输入通道stdin是否有可读取的信息,因此另开线程。

3.运行


demo下载

https://download.csdn.net/download/weixin_46424582/86412084


总结

例如:以上就是今天要讲的内容,具体可查看demo,仅仅演示了Qprocess的双向通信,实际应用场景还未验证。

有关关于Qt的QProcess进程间双向通信的更多相关文章

  1. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  2. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  3. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  4. Qt Designer的简单使用 - 2

    在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q

  5. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  6. ruby - 无法在 Ruby 中将 ffmpeg 作为子进程运行 - 2

    我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope

  7. Ruby 守护进程导致 ActiveRecord 记录器 IOError - 2

    我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame

  8. ruby - 在 ruby​​ 中生成一个进程,捕获 stdout,stderr,获取退出状态 - 2

    我想从ruby​​rake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调

  9. ruby-on-rails - 如何用不同的用户运行nginx主进程 - 2

    A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(

  10. ruby-on-rails - 关于 Ruby 的一般问题 - 2

    我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia

随机推荐