我正在尝试编写一个可以生成子进程并通过标准输出/输入与之通信的应用程序。为了掌握它,我尝试编写一个简单的应用程序,将消息发送到子进程,子进程将接收它并将其发回。经过坦率的荒谬审判和错误后,我设法向子进程发送消息,但我无法弄清楚如何将其发回。
这是我的尝试:
#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
我做错了什么?
答案 0 :(得分:3)
waitForXxx
未实现异步接口。读取和写入都是阻塞的,QFile
方法是无操作。
如果您希望这样做,请参阅this question了解如何实现非阻塞控制台I / O.
由于slave()
正在阻止,QProcess
不需要检查状态的循环。
您使用其阻止API使用QDataStream
,因此不必使用其信号。您还假设读取将返回完整的数据块。控制台I / O是面向流的,而不是面向消息的,因此您必须使用readyRead
事务来确保读取具有原子成功。 QProcess
指示仅表示某些数据可用。它可能只是一个字节。
如果您希望使用非阻止状态方法来处理argc[0]
和类似通信,请参阅this answer for one approach。
请注意,使用QCoreApplication::applicationFilePath()
启动self作为slave是不可靠的。请改用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";
}
boolean goLeft = false;
while (!s.isEmpty()) {
...
if (order >= 0) {
if(goLeft) {
s.push(new brach(endPoints.x, endPoints.y, b.length / 2, b.angle + 35)); // to draw left branch
s.push(new brach(endPoints.x, endPoints.y, b.length / 2, b.angle - 35)); // to draw right branch
goLeft = false;
} else {
s.push(new brach(endPoints.x, endPoints.y, b.length / 2, b.angle - 35)); // to draw right branch
s.push(new brach(endPoints.x, endPoints.y, b.length / 2, b.angle + 35)); // to draw left branch
goLeft = true;
}
order--;
}
}