2017-04-20 11 views
1

サブプロセスを生成し、標準出力/入力経由で通信するアプリケーションを作成しようとしています。ちょうど私はサブプロセスにメッセージを送信する単純なアプリケーションを書いてみましたし、サブプロセスはそれを受信し、それを返信します。率直に言って、試行錯誤した結果、私はサブプロセスにメッセージを受け取ることができましたが、返信する方法はわかりません。stdin/stdoutとQDataStreamを使ったQProcessとの通信

は、ここに私の試みです:

#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

) – fassl

答えて

2

QFileは、非同期インターフェイスを実装していません。読み取りと書き込みはブロックされ、waitForXxxメソッドはno-opsです。

ノンブロッキングコンソールI/Oの実装方法については、this questionを参照してください。

QFileがブロックしているので、slave()は状態を確認するループを必要としません。

QProcessはブロッキングAPIを使用しているため、シグナルの使用は不要です。また、読み込みによって完全なデータが返されると仮定します。コンソールI/Oはメッセージ指向ではなくストリーム指向です。したがって、読み取りがアトミックに成功したことを確認するには、QDataStreamトランザクションを使用する必要があります。 readyReadは、のデータがであることを示しています。それはちょうど1バイトかもしれません。

QProcessなどの通信にノンブロッキングのステートフルなアプローチを使用する場合は、this answer for one approachを参照してください。

argc[0]を使用して自己をスレーブとして起動することは信頼性がありません。代わりにQCoreApplication::applicationFilePath()を使用してください。私は与えられたQOIDeviceかどうかを伝えることができますどのように(読書のためのwhileループをダンプし、p.waitForReadyReadと交換

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"; 
} 
+0

作品以下の例、および以下の出力を生成非同期インターフェイスを実装していますか? – user697683

+0

通常はできません。 Qtでは、 'QFile'と' QBuffer'は同期しています。他のものはすべて非同期です(ソケットとポート)。自分で書くクラスや他のライブラリから使用するクラスについては、コードを調べて把握する必要があります。 –

関連する問題