首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过stdin/stdout和QDataStream与QDataStream通信

通过stdin/stdout和QDataStream与QDataStream通信
EN

Stack Overflow用户
提问于 2017-04-20 15:05:08
回答 1查看 2.4K关注 0票数 2

我正在尝试编写一个应用程序,它将生成一个子进程,并通过标准输出/输入与它进行通信。为了掌握它的诀窍,我尝试编写一个简单的应用程序,它会向子进程发送一条消息,子进程将接收到它并将其发回。坦白地说,经过大量的尝试和错误之后,我成功地向子进程发送了一条消息,但我想不出如何将它发回。

以下是我的尝试:

代码语言:javascript
复制
#include <QApplication>
#include <QDataStream>
#include <QFile>
#include <QDebug>
#include <QProcess>
#include <QThread>

#define dumpval(x) qDebug()<<#x<<'='<<x

void slave()
{
    QApplication::setApplicationName("slave");
    qSetMessagePattern("%{appname}: %{message}");
    qDebug()<<"started";
    QFile input;
    QFile output;
    dumpval(input.open(stdin, QFile::ReadOnly));
    dumpval(output.open(stdout, QFile::WriteOnly));

    QObject::connect(&output, &QIODevice::bytesWritten, [](int bytesWritten){dumpval(bytesWritten);});

    QDataStream inputStream(&input);
    QDataStream outputStream(&output);

    QByteArray data;
    while (true){
        inputStream>>data;
        dumpval(data);
        if (!data.isEmpty()) break;
        inputStream.resetStatus();
        QThread::sleep(1);
    }

    dumpval(output.isWritable());
    outputStream<<data;
    dumpval(output.waitForBytesWritten(-1));

    qDebug()<<"data written";
    qDebug()<<"stopped";
}

void master(QString path)
{
    QApplication::setApplicationName("master");
    qSetMessagePattern("%{appname}: %{message}");
    qDebug()<<"started";
    QProcess p;
    QObject::connect(&p, &QIODevice::bytesWritten, [](int bytesWritten){dumpval(bytesWritten);});
    p.setProgram(path);
    p.setArguments({"slave"});
    p.setProcessChannelMode(QProcess::ForwardedErrorChannel);
    p.start();
    p.waitForStarted();

    QDataStream stream(&p);
    QByteArray data = "this is a test";
    stream<<data;
    dumpval(p.waitForBytesWritten(-1));

    data.clear();

    while (true){
        stream>>data;
        dumpval(data);
        if (!data.isEmpty()) break;
        stream.resetStatus();
        QThread::sleep(1);
    }

    qDebug()<<"stopped";
}

int main(int argc, char** argv)
{
    if (argc == 1) master(argv[0]);
    else slave();
}

下面是这个代码的输出:

代码语言:javascript
复制
master: started
master: bytesWritten = 18
master: p.waitForBytesWritten(-1) = true
master: data = ""
slave: started
slave: input.open(stdin, QFile::ReadOnly) = true
slave: output.open(stdout, QFile::WriteOnly) = true
slave: data = "this is a test"
slave: output.isWritable() = true
slave: output.waitForBytesWritten(-1) = false
slave: data written
slave: stopped
master: data = ""
master: data = ""
master: data = ""
master: data = ""
master: data = ""
master: data = ""
^C

我做错了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-20 20:56:28

QFile不实现异步接口。读写是阻塞的,waitForXxx方法是无操作的.

如果您希望实现非阻塞控制台I/O,请参见this question

由于QFile是阻塞的,所以slave()不需要一个检查状态的循环。

您使用它的阻塞API使用QProcess,因此没有必要使用它的信号。您还假设读取将返回完整的数据块。控制台I/O是面向流的,而不是面向消息的,因此您必须使用QDataStream事务来确保读取成功。readyRead指示仅仅表明一些数据是可用的。可能只有一个字节。

如果您希望使用无阻塞的有状态方法来处理QProcess和类似的通信,请参见this answer for one approach

请注意,使用argc[0]作为从服务器启动self是不可靠的。使用QCoreApplication::applicationFilePath()代替。

下面的示例工作正常,并产生以下输出:

代码语言:javascript
复制
master: started
slave: started
slave: input.open(stdin, QFile::ReadOnly) = true
slave: output.open(stdout, QFile::WriteOnly) = true
slave: data = "this is a test\x00"
slave: data = ""
slave: inputStream.status() = 0
slave: stopped
master: data = "this is a test\x00"
master: data = ""
master: stopped
代码语言:javascript
复制
// https://github.com/KubaO/stackoverflown/tree/master/questions/process-echo-43523282
#include <QtCore>
#define dumpval(x) qDebug()<<#x<<'='<<x

void slave()
{
   QCoreApplication::setApplicationName("slave");
   qDebug()<<"started";
   QFile input, output;
   QDataStream inputStream{&input}, outputStream{&output};
   dumpval(input.open(stdin, QFile::ReadOnly));
   dumpval(output.open(stdout, QFile::WriteOnly));
   QByteArray data;
   do {
      inputStream >> data;
      outputStream << data;
      dumpval(data);
   } while (inputStream.status() == QDataStream::Ok && !data.isEmpty());
   dumpval(inputStream.status());
}

void master()
{
   QCoreApplication::setApplicationName("master");
   qDebug()<<"started";
   QProcess p;
   p.setProgram(QCoreApplication::applicationFilePath());
   p.setArguments({"slave"});
   p.setProcessChannelMode(QProcess::ForwardedErrorChannel);
   p.start();
   p.waitForStarted();

   QDataStream stream(&p);
   QByteArray data;
   stream << "this is a test" << QByteArray{};
   while (true) {
      stream.startTransaction();
      stream >> data;
      if (stream.commitTransaction()) {
         dumpval(data);
         if (data.isEmpty())
            break;
      } else
         p.waitForReadyRead();
   }
   p.waitForFinished();
}

int main(int argc, char** argv)
{
   QCoreApplication app(argc, argv);
   qSetMessagePattern("%{appname}: %{message}");
   if (app.arguments().size() < 2) master(); else slave();
   qDebug() << "stopped";
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43523282

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档