22.04.27 15:30 작성
·
1K
1
답변 1
0
2022. 04. 27. 16:19
안녕하세요. 김재우님
Qt 에서 제공하는 클래스 중에서 QProcess 클래스를 사용하면 외부프로그램을 실행하고 결과를 얻어올 수 있습니다.
결과를 얻어올 때 2가지 방법이 있습니다. 동기화 방식이 있고 비 동기화 방식이 있어요.
동기화 방식은 외부 프로그램을 실행시키면 결과가 끝날때 까지 프로그램을 블록킹 시키고, 결과를 받으면 실행 하는 방법입니다. 이 방법은 아래와 같이 하시면 됩니다.
QProcess process;
process.start("sh");
process.write("/home/my/test");
process.closeWriteChannel( );
process.waitForFinished( );
QByteArray my_data = process.readAll();
process.close( )
이렇게 해주면 됩니다. 그리고 waitForFinished( ) 함수에 인자가 없으면 끝날까지 기다립니다. 하지만 응답이 없어도 끝내게 하기 위해서 인자를 사용할 수 있습니다. 예를 들어 3초 후 끝나게 하고 싶다면 아래와 같이 사용하시면 됩니다.
process.waitForFinished( 3000 );
그리고 비 동기화 방식은 결과를 받을때까지 기다리는 것이 아니라 Siganl 과 Slot 을 연결해 비동기 방식으로 결과를 받을 수 있어요. 아래와 같이
connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(printMsg()));
함수를 사용하면 됩니다. 결과를 받아오면 printMsg( ) 함수를 실행합니다.
QString program = QString("/home/my/test"); myProcess->start(program);
2022. 05. 03. 15:08
안녕하세요. 재우님
QProcess 로 끝나고 얻어오는 것이 아니라 중간중간 결과를 가져오는 것이 라면 비 동기 방식으로 하면 가능합니다.
2022. 05. 04. 10:03
강사님 실례를 무릅쓰고 한번더 질문드립니다.
아래코드와 같이 hello를 1초마다 10번찍는 외부실행파일을 실행시켰습니다.
비동기방식으로 처리하여 1초마다 QT의 textedit에서도 찍고 싶은데.
실행결과 10의 문자열이 한꺼번에 출력됩니다. 비동기방식으로 중간중간 결과를 가져오고 싶은데..
이떻게 수정해야 될지 문의 드립니다. 참고로 윈도우에서 테스트중입니다.
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget)
{
ui->setupUi(this);
setWindowTitle("Netwrok Traffic Tester");
box = new QMessageBox;
connect(ui->pbt_Start, SIGNAL(pressed()),
this, SLOT(slotPbtStart()));
connect(ui->pbt_Stop, SIGNAL(pressed()),
this, SLOT(slotPbtStop()));
Process = new QProcess(this);
connect( Process, SIGNAL(readyReadStandardOutput()), this, SLOT(slotPrintProcessMsg()));
}
void Widget::slotPbtStart(){
QString _exePath = "C://hello.exe";
QStringList _arguments;
QByteArray rec_data;
ui->textEdit->clear();
Process->start(_exePath);
Process->waitForStarted();
}
void Widget::slotPbtStop()
{
Process->close();
}
void Widget::slotPrintProcessMsg()
{
QByteArray rec_data = Process->readAllStandardOutput();
ui->textEdit->append(rec_data);
}
2022. 05. 04. 11:28
안녕하세요. 김재우님,
slotPbtStart( ) 함수에서 Process->waitForStarted() 를 사용하면 동기식으로 받기 때문에 프로그램이 종료 될때 까지 기다렸다가 결과를 한번에 받아옵니다. 따라서 아래 예제와 같이 해보시면 어떨까 싶어서 ping 으로 실시간으로 결과를 받아오는 것을 예제로 만들어 보았습니다.
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QProcess>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
QProcess *m_process;
private slots:
void slot_pushButton();
void slotPrintProcessMsg();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QDateTime>
Widget::Widget(QWidget *parent)
: QWidget(parent), ui(new Ui::Widget)
, m_process(new QProcess)
{
ui->setupUi(this);
connect(ui->pushButton, SIGNAL(pressed()), this, SLOT(slot_pushButton()));
connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(slotPrintProcessMsg()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::slot_pushButton()
{
qDebug() << Q_FUNC_INFO;
QStringList arguments;
arguments << "-t" << "168.126.63.1";
m_process->start("ping", arguments);
}
void Widget::slotPrintProcessMsg()
{
QByteArray outData = m_process->readAllStandardOutput().trimmed();
QString currDt = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
qDebug("[%s] Received Message ---> [ %s ] ", currDt.toLocal8Bit().data(), outData.data() );
}
위와 같이 하시면 slotPrintProcessMsg( ) 함수 반복해 결과를 받아옵니다.
혹시 더 궁금하신것 있으면 언제든 질문해주세요.
2022. 05. 04. 14:08
감사합니다.
올려주신 코드를 따라 ping 테스트로 값을 실시간으로 가져오는 것을 확인했습니다.
하지만 제가 만든 hello world 실행파일이나, 제가 긍극적으로 하려고 하는 iperf3(네트워크 트래픽 테스트) 프로그램은 같은 방법을 사용하였지만 중간에 라인마다 값을 가져오지 않고 한꺼번에 가져 옵니다.
ping과 iperf3 프로그램은 실행될때 standard output 방식이 달라서 ping 프로그램과는 달리 iperf3는 중간값이 출력될때 시그널을 발생시키지 못하는 것 같습니다.
이 부분관련해서 조언을 주실 수 있으신지 미자막으로 문의드립니다.
감사합니다.
2022. 05. 04. 14:29
그렇다면 start( ) 함수 호출하기 전에
my_proc->setProcessChannelMode(QProcess::MergedChannels);
을 사용해보시거나
my_proc->setProcessChannelMode(QProcess::ForwardedOutputChannel);
을 사용하시면 어떨까 싶습니다.
그리고 iperf 에 --forceflush 라는 옵션을 사용해보심 어떨까 싶네요.
2022. 05. 18. 11:43
안녕하세요 강사님
결과가 궁금하실것 같아 말씀드립니다.
알려주신대로 iperf에서 --forceflush 옵션을 쓰니 원하는대로 라인바이라인 으로 출력이 됩니다.
다만 iperf3의 windows버전에서는 아직까지 --forceflush를 지원해 주지 않아 한참을 해맸습니다.
리눅스에서는 지원이 되어 가능은한데 window는 아직 성공하지 못했습니다.
큰도움이 되었습니다.
2022. 05. 03. 14:58
답변감사드립니다.
비동기로 처리하는 방식관련하여 추가 질문 드려도 될까요?
비동기 방식이라 함은 외부프로세스가 실행될때 그 프로세스 실행이 끝났을때 시그널 이벤트가 발생하고
해당 슬롯함수를 호출하는 것으로 보입니다. 따라서 동기방식과 얻어오는 값은 같은것 같은데
외부 프로그램을 실행하고 그 출력을 한꺼번에 얻어오는 것이 아니라 그 프로그램이 실행중일때
output 되는 메시지들을 라인단위로, 실시간으로 가져올 수 있는 방법은 없는지 문의드립니다.
예를들어 1초마다 hello world 1 일초후 hello world 2 일초후 hello world 3 이런식으로
출력되는 외부 프로세스를 실행시킬때 각 라인이 출력될때마다 값을 가져오고 싶습니다.
감사합니다.