我正在尝试编写一个应用程序,该应用程序将生成一个子进程并通过标准输出/输入与其进行通信。为了掌握它的窍门,我尝试编写一个简单的应用程序,它将向子进程发送消息,子进程将接收它并将其发回。经过坦率地荒谬的大量试验和错误后,我设法向子进程发送一条消息,但我不知道如何将其发回。
这是我的尝试:
#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();
}
这是这段代码的输出:
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
我做错了什么?
最佳答案
QFile
不实现异步接口(interface)。读取和写入是阻塞的,waitForXxx
方法是无操作的。
参见this question如果您愿意,可以了解如何实现非阻塞控制台 I/O。
自 QFile
正在阻塞,slave()
不需要检查状态的循环。
您使用QProcess
使用其阻塞 API,因此无需使用其信号。您还假设读取将返回完整的数据 block 。控制台 I/O 是面向流的,而不是面向消息的,因此您必须使用 QDataStream
事务以确保读取原子地成功。 readyRead
指示仅表明某些数据可用。它可能只是一个字节。
如果您希望使用非阻塞有状态方法来处理 QProcess
和类似的通信,请参阅 this answer for one approach .
请注意,使用 argc[0]
把自己作为奴隶开始是不可靠的。使用QCoreApplication::applicationFilePath()
相反。
下面的示例有效,并产生以下输出:
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
// 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";
}
关于c++ - 通过 stdin/stdout 和 QDataStream 与 QProcess 通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43523282/