• Qt之进程通信-QProcess(含源码+注释)


    一、QProcess进程通信示例

    下方为默认程序启动通信示例
    在这里插入图片描述
    下方为默认程序为空,然后指定启动的应用程序通信
    在这里插入图片描述

    二、QProcess通信个人理解

    1. 主进程给子进程发送数据:直接通过QProcess对象的write函数写入数据(给通过start函数启动的进程,并且写入数据需要以“\n”结尾,方便子进程识别且读取数据);
    2. 主进程接收数据:直接关联QProcess的readyReadStandardError()、readyReadStandardOutput()信号可接收读取错误输出和数据输出;
    3. 子进程接收数据:本文通过QTextStream和std::string对象读取数据,且两者对象都是在线程中循环识别数据,并通过信号输出显示到主界面中;
    4. 子进程发送数据:子进程通过QFile打开stdout流通道,直接通过QFile的write函数写入数据即可(此处不需要以“\n”结尾主线程都可以读取数据)。

    三、源码

    MainWindowProcessSender

    MainWindowProcessSender.h

    #ifndef MAINWINDOWPROCESSSENDER_H
    #define MAINWINDOWPROCESSSENDER_H
    
    #include 
    #include 
    
    namespace Ui {
    class MainWindowProcessSender;
    }
    
    class MainWindowProcessSender : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindowProcessSender(QWidget *parent = nullptr);
        ~MainWindowProcessSender();
    
    private slots:
        /**
         * @brief on_btnStartProcess_clicked 启动进程信号槽
         */
        void on_btnStartProcess_clicked();
    
        /**
         * @brief on_readyReadStandardError 错误信息信号槽
         */
        void on_readyReadStandardError();
    
        /**
         * @brief on_readyReadStandardOutput 输出信息信号槽
         */
        void on_readyReadStandardOutput();
    
        /**
         * @brief on_btnSend_clicked 数据发送信号槽
         */
        void on_btnSend_clicked();
    
    private:
        Ui::MainWindowProcessSender *ui;
    
        QProcess    m_process;  // 进程对象
    
        QString     m_path; // 子进程路径
    
    };
    
    #endif // MAINWINDOWPROCESSSENDER_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    MainWindowProcessSender.cpp

    #include "MainWindowProcessSender.h"
    #include "ui_MainWindowProcessSender.h"
    
    #include 
    #include 
    #include 
    
    MainWindowProcessSender::MainWindowProcessSender(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindowProcessSender)
        , m_path("")
    {
        ui->setupUi(this);
        // 关联数据信号
        connect(&m_process, &QProcess::readyReadStandardError, this, &MainWindowProcessSender::on_readyReadStandardError);
        connect(&m_process, &QProcess::readyReadStandardOutput, this, &MainWindowProcessSender::on_readyReadStandardOutput);
    }
    
    MainWindowProcessSender::~MainWindowProcessSender()
    {
        // 写入结束指令,使子进程读取线程停止
        m_process.write(u8"%kill%\n");
        // 结束子进程
        m_process.terminate();
        // 等待子进程结束
        m_process.waitForFinished(5000);
        delete ui;
    }
    
    void MainWindowProcessSender::on_btnStartProcess_clicked()
    {
        QString path;
        if(!m_path.isEmpty()) {
            QFile file(m_path);
            if(!file.exists()) {
                QMessageBox::information(this, u8"提示", u8"启动程序不存在,请自主选择程序");
                m_path = "";
                return;
            }
            path = m_path;
        }
        else {
            path = QFileDialog::getOpenFileName(this, u8"选择启动程序", u8"./", "*.exe");
        }
        m_process.start(path);
        ui->btnStartProcess->setEnabled(false);
    }
    
    void MainWindowProcessSender::on_readyReadStandardError()
    {
        // 错误信息追加
        ui->plainTextEdit->appendPlainText("Error:" + m_process.readAllStandardError());
    }
    
    void MainWindowProcessSender::on_readyReadStandardOutput()
    {
        // 通信数据追加
        QByteArray data = m_process.readAllStandardOutput();
        ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit(data));
    }
    
    void MainWindowProcessSender::on_btnSend_clicked()
    {
        // 发送数据
        if(!m_process.isOpen()) {
            return;
        }
        // 写入数据
        m_process.write((ui->lineEdit->text()).toStdString().data());
        // 写入结束符
        m_process.write("\n");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    MainWindowProcessSender.ui

    
    <ui version="4.0">
     <class>MainWindowProcessSenderclass>
     <widget class="QMainWindow" name="MainWindowProcessSender">
      <property name="geometry">
       <rect>
        <x>0x>
        <y>0y>
        <width>400width>
        <height>300height>
       rect>
      property>
      <property name="windowTitle">
       <string>MainWindowProcessSenderstring>
      property>
      <widget class="QWidget" name="centralWidget">
       <layout class="QGridLayout" name="gridLayout">
        <item row="0" column="0">
         <widget class="QLineEdit" name="lineEdit">
          <property name="text">
           <string/>
          property>
         widget>
        item>
        <item row="0" column="1">
         <widget class="QPushButton" name="btnSend">
          <property name="text">
           <string>发送string>
          property>
         widget>
        item>
        <item row="0" column="2">
         <widget class="QPushButton" name="btnStartProcess">
          <property name="text">
           <string>启动通信程序string>
          property>
         widget>
        item>
        <item row="1" column="0" colspan="3">
         <widget class="QPlainTextEdit" name="plainTextEdit"/>
        item>
       layout>
      widget>
      <widget class="QMenuBar" name="menuBar">
       <property name="geometry">
        <rect>
         <x>0x>
         <y>0y>
         <width>400width>
         <height>23height>
        rect>
       property>
      widget>
      <widget class="QToolBar" name="mainToolBar">
       <attribute name="toolBarArea">
        <enum>TopToolBarAreaenum>
       attribute>
       <attribute name="toolBarBreak">
        <bool>falsebool>
       attribute>
      widget>
      <widget class="QStatusBar" name="statusBar"/>
     widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    ui>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    MainWindowProcessRecv

    MainWindowProcessRecv.h

    #ifndef MAINWINDOWPROCESSRECV_H
    #define MAINWINDOWPROCESSRECV_H
    
    #include 
    #include 
    #include 
    
    namespace Ui {
    class MainWindowProcessRecv;
    }
    
    class MainWindowProcessRecv : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindowProcessRecv(QWidget *parent = nullptr);
        ~MainWindowProcessRecv();
    
        void appendText(QString str);
    
    signals:
        /**
         * @brief sigDataRead 数据输入信号
         * @param str 输入数据
         */
        void sigDataRead(QString str);
    
    private slots:
        /**
         * @brief on_btnSend_clicked数据发送信号槽
         */
        void on_btnSend_clicked();
    
        /**
         * @brief on_btnStartRecv_clicked 数据接收信号槽
         */
        void on_btnStartRecv_clicked();
    
        /**
         * @brief on_loopReadInData 数据接收处理信号槽
         */
        void on_loopReadInData();
    
    private:
        Ui::MainWindowProcessRecv   *ui;
    
        bool                        m_readFlag;         // 数据接收标记
    };
    
    #endif // MAINWINDOWPROCESSRECV_H
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    MainWindowProcessRecv.cpp

    #include "MainWindowProcessRecv.h"
    #include "ui_MainWindowProcessRecv.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    MainWindowProcessRecv::MainWindowProcessRecv(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindowProcessRecv)
        , m_readFlag(false) // 读取标记默认false
    {
        ui->setupUi(this);
        // 连接输入流数据信号槽
        connect(this, &MainWindowProcessRecv::sigDataRead, this, [=](QString str){
            ui->editDebug->appendPlainText(str);
        });
    }
    
    MainWindowProcessRecv::~MainWindowProcessRecv()
    {
        // 读取标志主动设置为false
        m_readFlag = false;
        delete ui;
    }
    
    void MainWindowProcessRecv::appendText(QString str)
    {
        ui->editDebug->appendPlainText(str);
    }
    
    void MainWindowProcessRecv::on_btnSend_clicked()
    {
        // 打开输出流通道
        QFile file;
        if(!file.open(stdout, QIODevice::ReadWrite)) {
            qDebug() << u8"打开失败";
            return;
        }
    
        // 写入数据
        file.write(ui->lineEdit->text().toLocal8Bit());
        // 关闭输出流通道
        file.close();
    }
    
    void MainWindowProcessRecv::on_loopReadInData()
    {
        while(m_readFlag) {
    #if 0
            // 通过文本流读取数据(因为stdin本身输入的就是流数据)
            QTextStream stream(stdin);
            stream.setCodec("utf8");    // 指定编码类型防止乱码
            QString str;
            stream.readLineInto(&str);  // 读取数据(读取一行数据,其中以\n"或"\r\n为结束标记)、
            // 数据接收信号
            emit sigDataRead(str);
    #else
            // 创建数据接收数据
            std::string str;
            // 读取数据
            std::getline(std::cin, str);
            // 数据接收信号
            emit sigDataRead(QString::fromStdString(str));
    #endif
            // 读取标记赋值(通过主进程发送数据识别关闭)
            m_readFlag = 0 != str.compare(u8"%kill%");
        }
    }
    
    void MainWindowProcessRecv::on_btnStartRecv_clicked()
    {
        if(m_readFlag) {
            m_readFlag = false;
            ui->btnStartRecv->setText(u8"开始接收");
        }
        else {
            m_readFlag = true;
            ui->btnStartRecv->setText(u8"停止接收");
            // 以线程启动数据读取
            QtConcurrent::run(this, &MainWindowProcessRecv::on_loopReadInData);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    MainWindowProcessRecv.ui

    
    <ui version="4.0">
     <class>MainWindowProcessRecvclass>
     <widget class="QMainWindow" name="MainWindowProcessRecv">
      <property name="geometry">
       <rect>
        <x>0x>
        <y>0y>
        <width>400width>
        <height>300height>
       rect>
      property>
      <property name="windowTitle">
       <string>MainWindowProcessRecvstring>
      property>
      <widget class="QWidget" name="centralWidget">
       <layout class="QGridLayout" name="gridLayout">
        <item row="0" column="0">
         <widget class="QLineEdit" name="lineEdit">
          <property name="text">
           <string/>
          property>
         widget>
        item>
        <item row="0" column="1">
         <widget class="QPushButton" name="btnSend">
          <property name="text">
           <string>发送string>
          property>
         widget>
        item>
        <item row="0" column="2">
         <widget class="QPushButton" name="btnStartRecv">
          <property name="text">
           <string>开始接收string>
          property>
         widget>
        item>
        <item row="1" column="0" colspan="3">
         <widget class="QPlainTextEdit" name="editDebug"/>
        item>
       layout>
      widget>
      <widget class="QMenuBar" name="menuBar">
       <property name="geometry">
        <rect>
         <x>0x>
         <y>0y>
         <width>400width>
         <height>23height>
        rect>
       property>
      widget>
      <widget class="QToolBar" name="mainToolBar">
       <attribute name="toolBarArea">
        <enum>TopToolBarAreaenum>
       attribute>
       <attribute name="toolBarBreak">
        <bool>falsebool>
       attribute>
      widget>
      <widget class="QStatusBar" name="statusBar"/>
     widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    ui>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    总结

    QProcess启动子进程后,主进程关闭会带着子进程一起关闭,但是如果通过startDetached启动子进程写入的数据将读取不到,大概如此,网络中还包含子进程使用QSocketNotifier关联数据读取,我个人并未尝试成功,后期打算再尝试一下。

    相关文章

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

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

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

  • 相关阅读:
    vue重修之Vuex【下部】
    北京何氏眼科专家:老花眼无法“自愈”!尽早预防是关键!
    LeetCode高频题69. x 的平方根,二分法搞定,非常简单
    Mybatis开启日志
    基于PHP+MySQL的在线学习网站系统
    【实验作业】微处理器原理与应用 CPUHomework3【子程序汇编实验 流程图 十六进制数转十进制数 键盘录入 屏幕显示 闰年判断 两位数求和 汇编小程序】
    RF学习——器件的非线性失真分析
    关于网络协议的若干问题(四)
    k8s配置deployment解读
    基于Python实现可视化分析中国500强排行榜数据的设计与实现
  • 原文地址:https://blog.csdn.net/wj584652425/article/details/133551497