QT возвращает результат команды оболочки без блокировки

В qt я пытаюсь запустить следующую команду оболочки:

 arp | grep -i 'test'

В настоящее время у меня есть следующий код:

QString Network::getMac(){
     QProcess sh;
     sh.start("sh");
     sh.waitForStarted();
     sh.write("arp  -n| grep -i 'test'");
     sh.closeWriteChannel();
     sh.waitForFinished();
     QString line=  sh.readAll().replace("\n","").toLower();
     return line;
}

Я хочу использовать Mac, например. подобно:

  QString mac = objectOfClassThatHasTheFunction->getMac();

Он отлично работает, но проблема в том, что это занимает очень много времени и блокирует программу. Документы говорят waitForFinished Blocks until the process has finished and the finished() signal has been emitted, or until msecs milliseconds have passed. Но как я могу вернуть результат без блокировки? Как мне запустить QProcess без блокировки, когда я хочу использовать результат?

Я могу ускорить процесс, используя arp -n, но я хочу узнать, как правильно использовать qprocess.


person Sven van den Boogaart    schedule 29.06.2020    source источник


Ответы (2)


*bool QProcess::startDetached(qint64 pid = nullptr)

 QProcess sh;
 sh.setProgram("sh");
 sh.setArguments({"arp -n | grep -i 'test'"});
 connect(&sh,&QProcess::readyReadStandardOutput,this,&YOUR_CLASS::YOUR_SLOT);
 sh.start(); //EDIT: startDetached() is not emitting signals

YOUR_CLASS::YOUR_SLOT — это слот, в котором вы можете получить стандартный вывод

Позаботьтесь о области действия переменной sh. Он может быть уничтожен, если объявлен в функции.

person smacker    schedule 29.06.2020
comment
Я видел сигналы слота для qprocess, но как вы возвращаете их из вызова функции? - person Sven van den Boogaart; 29.06.2020
comment
Таким образом, вам не нужно возвращать его. В своем слоте просто используйте: sh.readAllStandardOutput(). Слот будет вызываться асинхронно, когда вы получите текст на стандартный вывод и просто отобразите его или обработаете. - person smacker; 29.06.2020
comment
Я хочу вернуть его, например. QString mac = someClass->getMac(); - person Sven van den Boogaart; 30.06.2020
comment
У вас есть три подхода: 1. Блокировка основного потока до тех пор, пока вы не получите информацию от исполняемого процесса. Вы это реализовали. 2. Без блокировки основного потока, как в первом Г.М. пример. 3. Асинхронный, как в моем примере. Таким образом, вы получите то, что вам нужно в слоте, подключенном к сигналу readyReadStandardOutput. Этот сигнал будет испускаться в любое время, когда ваша команда оболочки что-то выводит. Это место, где вы будете получать данные. - person smacker; 30.06.2020

Если вы действительно должны дождаться результата, вы можете использовать цикл обработки событий (непроверенный)...

QString Network::getMac ()
{
  QProcess sh;
  QEventLoop el;
  QObject::connect(&sh, &QProcess::started, &el, &QEventLoop::quit);
  sh.start("sh");
  el.exec();
  QObject::connect(&sh, &QProcess::finished, &el, &QEventLoop::quit);
  sh.write("arp  -n| grep -i 'test'");
  el.exec();
  QString line = sh.readAll().replace("\n","").toLower();
  return line;
}

Однако в целом вам следует подключаться к различным QProcess сигналам и действовать в соответствии с ними. Без проверки ошибок это может быть что-то вроде...

void Network::getMac ()
{
  auto *sh = QProcess;
  QObject::connect(&sh, &QProcess::started,
                   [sh]()
                   {

                     /*
                      * The process has started so write the command.
                      */
                      sh->write("arp  -n| grep -i 'test'");
                   });
  QObject::connect(&sh, &QProcess::finished,
                   [sh]()
                   {

                     /*
                      * The process has finished so fetch and use the
                      * data.
                      */
                     QString line = sh->readAll().replace("\n","").toLower();
                     process(line);

                     /*
                      * The QProcess `sh' was new'd so we need to make
                      * sure it's deleted when control is returned to
                      * the event loop.
                      */
                     sh->deleteLater();
                   });
  sh->start("sh");
}
person G.M.    schedule 29.06.2020
comment
Я хочу вернуть результат, если это возможно, не дожидаясь, это даже лучше. - person Sven van den Boogaart; 29.06.2020
comment
Я не совсем понимаю, что вы имеете в виду под "...return the resullt, if it is possible without waiting...". Выполнение команды займет конечное количество времени — от этого никуда не деться. Использование локального QEventLoop позволяет Qt обрабатывать другие события, ожидая завершения QProcess. Извините, если я неправильно понял проблему. - person G.M.; 29.06.2020
comment
извините, это было в ответ на «если вам действительно нужно дождаться результата», я думал, вы намекаете, что ждать не нужно. - person Sven van den Boogaart; 29.06.2020