如何与孩子QProcess互动?

时间:2014-06-04 16:41:20

标签: c++ ipc qt5 qprocess

在我的程序中,我有一个子进程,当父进程需要它时,它与指定给它的串口交互。例如,父进程通过发送以下命令命令子进程从打开的端口读取一定数量的字节:read 100 1000。子进程成功启动并打开端口,我可以看到消息port openned successfully!,但从那以后它就不会读取父命令。

这是儿童源代码:

SerialPortHandler.h

#ifndef SERIALPORTHANDLER_H
#define SERIALPORTHANDLER_H

#include <QObject>
#include <QSocketNotifier>
#include <QTextStream>
#include <QSerialPort>
#include <QFile>
#include <QTimer>
#include <QDebug>
#include <QtCore>

enum CommandType { READ, WRITE, BAD, UNKNOWN };

class SerialPortHandler : public QObject
{
    Q_OBJECT
public:
    explicit SerialPortHandler(QString portname, QString baudrate, QObject *parent = 0);

signals:

public slots:
    void execmd();
    bool open(const QString& portname, const QString& baudrate);
    qint64 read(char * buff, const qint64 size, const qint32 timeout);
    QString convertToCaseInsensitiveRegExp(QString str);
    CommandType analyze(const QString& line);
    qint64 getNum(const QString &line, int index);
    void reply(char *buff);

private:
    QSocketNotifier *innotif;
    QSerialPort *sp;
    QTimer *timer;

};

#endif // SERIALPORTHANDLER_H

SerialPortHandler.cpp

#include "SerialPortHandler.h"
#include <unistd.h>
#include <limits>

SerialPortHandler::SerialPortHandler(QString portname, QString baudrate, QObject *parent) :
    QObject(parent)
{
    timer = new QTimer(this);
    sp = new QSerialPort(this);
    if(!open(portname, baudrate)) {
        qDebug() << sp->error() << sp->errorString();
        exit(sp->error());
    }
    innotif = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read, this);
    connect(innotif, SIGNAL(activated(int)), this, SLOT(execmd()));
}

void SerialPortHandler::execmd()
{
    qDebug() << "command received. analyzing...";
//    qint64 nbr = -1, size = -1;
//    qint32 timeout = -1;
//    char * buff = 0;
//    QTextStream in(stdin);
//    QString ln = in.readAll();
//    switch (analyze(ln)) {
//    case READ:
//        size = getNum(ln, 1);
//        timeout = getNum(ln, 2);
//        if(size > -1 && timeout > -1)
//            nbr = read(buff, size, timeout);
//        if(nbr > -1)
//            reply(buff);
//        break;
//    default:
//        break;
//    }
}

bool SerialPortHandler::open(const QString &portname, const QString &baudrate)
{
    sp->setPortName(portname);
    if (!sp->open(QIODevice::ReadWrite) ||
            !sp->setBaudRate(baudrate.toInt()) ||
            !sp->setDataBits(QSerialPort::Data8) ||
            !sp->setParity(QSerialPort::NoParity) ||
            !sp->setStopBits(QSerialPort::OneStop) ||
            !sp->setFlowControl(QSerialPort::NoFlowControl)) {
        return false;
    }
    sp->clear();
    qDebug() << "port openned successfully!";
    return true;
}

//day light wont affect this timer so the system wont freeze
qint64 SerialPortHandler::read(char *buff, const qint64 size, const qint32 timeout)
{
    qint64 numbytesread = -1;
    timer->start(timeout);
    while (true) {
        if(timer->remainingTime() > 0) {
            return -1;
        }
        if((sp->isReadable() && sp->bytesAvailable() > 0) ||
                (sp->isReadable() && sp->waitForReadyRead(10))) {
            numbytesread += sp->read(buff, size);
        }
        if(numbytesread < 0) {
            return -1;
        }
        if(numbytesread == size) {
            break;
        }
    }
    return numbytesread;
}

void SerialPortHandler::notify()
{

}

QString SerialPortHandler::convertToCaseInsensitiveRegExp(QString str)
{
    QString result;
    for(int i = 0 ; i < str.size() ; ++i) {
        result.append("[");
        result.append(str.at(i).toLower());
        result.append(str.at(i).toUpper());
        result.append("]");
    }
    return result;
}

CommandType SerialPortHandler::analyze(const QString &line)
{
    QString read, write;
    read = convertToCaseInsensitiveRegExp("read");
    write = convertToCaseInsensitiveRegExp("write");
    if(line.contains(QRegExp(QString("^.*%1\\s+[1-9]\\d*\\s+[1-9]\\d*.*").arg(read)))) {
        return READ;
    }
    return UNKNOWN;
}

qint64 SerialPortHandler::getNum(const QString& line, int index) {
    QStringList args(line.split(QRegExp("\\s+")));
    bool done;
    qint64 size = args.at(index).toInt(&done, 10);
    if(done) {
        return size;
    }
    return -1;
}

void SerialPortHandler::reply(char * buff) {
    QDataStream out(stdout);
    out << buff;
}

的main.cpp

#include <QCoreApplication>
#include <QDebug>
#include "SerialPortHandler.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    if(argc != 3) {
        qDebug() << "usage:" << argv[0] << "port" << "baudrate";
    } else {
        SerialPortHandler *sph = new SerialPortHandler(argv[1], argv[2]);
    }

    return a.exec();
}

我的父进程包含以下内容:

ParentProcess.h

#ifndef PARENTPROCESS_H
#define PARENTPROCESS_H

#include <QObject>
#include <QtCore>

class ParentProcess : public QObject
{
    Q_OBJECT
public:
    explicit ParentProcess(QObject *parent = 0);

signals:

public slots:

private slots:
    void sendRead();
    void writeSomething();
    void handleError(QProcess::ProcessError error);
private:
    QProcess *p;

};

#endif // PARENTPROCESS_H

ParentProcess.cpp

#include "ParentProcess.h"
#include <QDebug>

ParentProcess::ParentProcess(QObject *parent) :
    QObject(parent)
{

    p = new QProcess(this);
    connect(p, SIGNAL(readyReadStandardOutput()), this, SLOT(sendRead()));
    connect(p, SIGNAL(readyReadStandardError()), this, SLOT(sendRead()));
    connect(p, SIGNAL(started()), this, SLOT(writeSomething()));
    connect(p, SIGNAL(error(QProcess::ProcessError)), this, SLOT(handleError(QProcess::ProcessError)));
    QStringList args;
    args << "/dev/ttyUSB0" << "115200";
    p->start("/home/moki/Work/Programs/build-serialio-Desktop_Qt_5_3_0_GCC_64bit-Debug/serialio", args, QProcess::ReadWrite);
}

void ParentProcess::sendRead() {
    qDebug() << "data:" << p->readAllStandardError() << p->readAllStandardOutput();
}

void ParentProcess::writeSomething() {

    qDebug() << "writing";
    QString cmd = "read 10 10000\n";
    qint64 a = p->write(cmd.toStdString().c_str());
    qDebug() << "wrote:" << a;
}

void ParentProcess::handleError(QProcess::ProcessError error)
{
    switch (error) {
    case QProcess::FailedToStart:
        qDebug() << "failed to start";
        break;
    case QProcess::Crashed:
        qDebug() << "crashed.";
        break;
    default:
        break;
    }
}

的main.cpp

#include <QCoreApplication>
#include "ParentProcess.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    ParentProcess p;

    return a.exec();
}

我在SO中看到了其他几个答案,但没有一个能解决我的问题。正如您所看到的,我的子进程不应该完成并退出。只要父进程愿意,它将继续启动。以这种方式使用QProcess启动的流程是否正确?

1 个答案:

答案 0 :(得分:0)

我将代码更改为以下内容,现在它正在运行。但我还不明白为什么这段代码有效,而我原来的代码没有。

父进程源中的

我更改了构造函数,如下所示:

ParentProcess::ParentProcess(QObject *parent) :
    QObject(parent)
{

    p = new QProcess(this);
    connect(p, SIGNAL(error(QProcess::ProcessError)), this, SLOT(handleError(QProcess::ProcessError)));
    connect(p, SIGNAL(readyRead()), this, SLOT(sendRead()));
    connect(p, SIGNAL(started()), this, SLOT(writeSomething()));
    QStringList args;
    args << "/dev/ttyUSB0" << "115200";
    p->setProcessChannelMode(QProcess::MergedChannels);
    p->start("/home/moki/Work/Programs/build-serialio-Desktop_Qt_5_3_0_GCC_64bit-Debug/serialio", args, QProcess::ReadWrite);
}

sendRead()函数:

void ParentProcess::sendRead() {
    int bytes = p->bytesAvailable();
    qDebug() << "data:" << p->read(bytes);
}

最后,writeSomething()到:

void ParentProcess::writeSomething() {
    qDebug() << "gonna write.";

    if(p->state() == QProcess::Running) {
        qDebug() << "writing";
        QString cmd = "read 10 10000\n";
        qint64 a = p->write(cmd.toStdString().c_str());
        qDebug() << "wrote:" << a << "bytes.";
    }
}

现在它有效。如果有人能够向我解释这一点,我将非常感激。