子进程stdin没有得到数据,由父进程发送

Posted

技术标签:

【中文标题】子进程stdin没有得到数据,由父进程发送【英文标题】:Child process stdin doesn't get data, sent by parent process 【发布时间】:2011-09-17 21:37:59 【问题描述】:

父进程将字符串"Message\n" 写入子进程stdin。但是子进程没有收到它。代码哪里出了问题?

Qt 4.7.3

父进程代码:

// class TestParent : public QMainWindow
void TestParent::createChildProcess()

    childProcess = new QProcess( this );
    connect( childProcess, SIGNAL( started() ),
        this, SLOT( childProcessStarted() ) );
    connect( childProcess, SIGNAL( bytesWritten( qint64 ) ),
        this, SLOT( bytesWritten( qint64 ) ) );
    childProcess->start( "TestChild.exe", QProcess::ReadWrite );


void TestParent::writeToChildProcessOutput()

    qint64 bytesWritten = childProcess->write( "Message\n" );
    qDebug() << "ret: " << bytesWritten << " bytes written";


void TestParent::bytesWritten()

    qDebug() << "slot: " << bytesWritten << " bytes written";

子进程代码:

// class TestChild : public QMainWindow
void TestChild::TestChild()
    // QFile TestChild::input;
    connect( &input, SIGNAL( readyRead() ),
        this, SLOT( readInput() ) );
    input.open( 0, QIODevice::ReadOnly ); // stdin


void TestChild::readInput()

    QString line;
    line.append( '(' );
    line.append( QString::number( input.bytesAvailable() ) )
    line.append( ')' );
    line.append( input.readAll() );

    list.append( line ); // add line to QListView

【问题讨论】:

TestChild 是 QProcess 吗?并且输入是 QIODevice,而不是子类? @Chris:不,TestChild - 子进程的主窗口对象。在父进程中,我们使用childProcess 对象创建子进程。我的错误:input 是 QFile,谢谢。 【参考方案1】:

没有办法在 Qt 事件循环中为 stdin/stdout 事件进行可移植的连接。以下适用于非 Windows 平台:

QSocketNotifier *n1 = new QSocketNotifier(0, QSocketNotifier::Read, this);
connect(n1, SIGNAL(activated(int)), this, SLOT(readInputChannel()));

QSocketNotifier *n2 = new QSocketNotifier(0, QSocketNotifier::Exception, this);
connect(n2, SIGNAL(activated(int)), this, SLOT(brokenInputChannel()));

“0”是文件描述符(stdin)。

我将使用上述方法,然后通过从标准输入读取并生成信号的阻塞线程在 Windows 上模拟类似的东西:

class StdinThread : public QThread

    Q_OBJECT
signals:
    void incomingData(QByteArray data);

public:
    void run(void)
    
         char buf[1024];
         while (1)
         
             int sz = fread(buf, 1, 1024, stdin);
             if (sz == 0)
                return;
             emit incomingData(QByteArray(buf, sz));
         
     
;

那么,在子进程中:

StdinThread *t = new StdinThread(this);
connect(t, SIGNAL(incomingData(QByteArray)), this, SLOT(processInputData(QByteArray)));
connect(t, SIGNAL(finished()), this, SLOT(brokenInputChannel()));
t->run();

【讨论】:

+1。这很有帮助,谢谢。你不知道QProcess::write(标准输入管道)是否适用于Windows?换句话说:我可以写子进程的标准输入吗? 是的,你可以。 Windows 支持管道。只需注意缓冲即可。【参考方案2】:

文档说QFile 永远不会发出信号readyRead()

但有一个私有类:QWinEventNotifier in src/corelib/kernel/qwineventnotifier_p.h(link) 可能与 GetStdHandle(STD_INPUT_HANDLE) 一起使用。

另一种选择是在专用线程内使用阻塞循环等待输入:

QTextStream cin(stdin, QIODevice::ReadOnly);
while(!cin.atEnd())

   QString line = cin.readLine();
   emit newLine(line);

您还可以查看其他 RPC 方法(例如 QLocalSocketQSharedMemory)。

【讨论】:

谢谢,将尝试 QWinEventNotifier。但是问题仍然存在:我已经启动了一个计时器,每个 X 毫秒写入日志文件input.bytesAvailable(),它总是写入0bytesAvailable() 在这里的用法是否也不正确? QSharedMemory 没有尝试。但是关于QLocalSocketQLocalServer(Windows 中的命名管道):我仍然需要交换管道名称(每个QLocalServer 1 个)。除了标准输入/标准输出,还有其他简单的方法来发送管道名称吗? 1.您无法使用 C/C++ 标准库查看标准输入缓冲区,因此如果 Qt 也不允许这样做也就不足为奇了。 2.您可以将管道名称作为子流程参数发送。 我应该用什么来进行孩子->父母的交流?还在使用标准输出? "然后您可以通过调用 write() 写入进程的标准输入,并通过调用 read()、readLine() 和 getChar() 读取标准输出。" (doc.qt.nokia.com/latest/qprocess.html)【参考方案3】:

我认为您需要做的是从实际的 QProcess 对象中读取数据(在本例中为 childProcess,如果我理解正确的话)。

注意QProcess实际上是QIODevice的子类,还要特别注意以下函数:

QProcess::setReadChannel()
QProcess::readAllStandardOutput()

您应该能够使用 QProcess 对象的 readyRead() 信号,而不是创建 QFile 来尝试读取标准输入。这不起作用的原因是您的 QFile 与您的 MainWindow 关联的进程,而不是您的子进程。

【讨论】:

没有。 childProcess 是父进程中的控制对象。使用childProcess 对象父进程打印字符串到子进程的stdin (TestParent::writeToChildProcessOutput())。子进程应该从stdin 读取该字符串。所以在子进程中QFile input对象的readyRead()信号应该被发射(但没有readyRead()信号发射,TestChild::readInput()槽没有被调用)。

以上是关于子进程stdin没有得到数据,由父进程发送的主要内容,如果未能解决你的问题,请参考以下文章

带子进程的双向管道

进程管理

当父进程为 64 位时,StdIN/StdOUT 管道出现问题

golang父进程通过管道向子进程传递数据

杀死父进程后将标准输入传递给子进程

linux进程管理