Название: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: Denjs от Сентябрь 13, 2009, 23:19 Всем кто не разобрался с чтением в дочерней программе запущенной от QProcess потока stdin - посвящается.
Напомню проблему: Нас (мы - консольная прогрмамма) запустили как дочерний процесс с помошью QProcess, или чего-либо другого и собираются общаться с нами через stdin|stdout|stderr. Мы, естественно полностью QT-шная программа и хотим работать с данными потоками красиво, событийно-ориентированно и вообще не напрягаться. Но пока, судя по всему, не напрягаясь если и получалось - то получалось не у многих. В общем, т.к. вопросов было больше чем ответов - отмечу 3 ключевых "пунктега" касающихся чтения stdin через QFile (по крайней мере для QT 4.5 под Linux). 1) чтение с помошью QFile данных из файла stdin - блокирующее. пока не поступит хоть один байт данных - повиснем. 2) но и узнать при этом, поступило-ли что вам на вход, тоже нельзя - QFile::byteasAvalable() не изменяет свого показания пока не считан хоть один байт данных из потока, а QFile::ReadyRead() не срабатывает принципиально. 3) и, наконец, касательно stdout: для того что бы данные из дочернего потока сразу попадали в QProcess - делайте в дочернем процесе после записи в stdOut функцию QFile::flush() исходя из этих трех простых пунктов, тестового исходника из одного ранее появившегося поста (http://www.prog.org.ru/index.php?topic=5677.msg25539#msg25539) и родился класс stdInReader. Исходники ниже, в приложении - сорсы 2-х приложений для тестирования/демонстрации. Класс простой - генерирует сигнал с данными, которые поступили на stdin, и обрабатывает 2 слота - для отсылки данных на stdout и stderr. UseCase работы прост: Создаем объект, делаем ему init(), если ноль на выходе - вживляем его в нервную систему сигнал-слотов объектов вашего приложения и после делаем ему run(). Все: при поступлении данных на sdtin - побежал сигнал received_StdIn(QByteArray) а далее сами разберетесь т.д. Так сказать, "в лучших традициях индийского быдлокодинга", представляею работающий прототип: stdInReader.h : Код: /* stdInReader.h stdInReader.cpp : Код:
- как минимум надо сделать нормальное завершение. - можно сделать его наследником QIODevice - но зачем? впрочем как решите - пусть так и будет. главное что бы сорсы обновлялись... пока выкладывайте здесь, если кто будет обновлять... дальше посмотрим. Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: Denjs от Сентябрь 13, 2009, 23:55 Пока замечена одна проблема.
Не корректно (а вернее "вообще никак") не обрабатывается закрытие потока stdin... в иттоге - запуск testcon.bin из следующего bash скрипта вгоняет программу в страшный бесконечный цикл... Код: #!/bin/bash исправлять уже сегодня не буду. на неделе если дойдут руки если никто не исправит ) Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: pastor от Сентябрь 14, 2009, 00:27 Оформи тему в качестве статьи и я перенесу её в раздел Уроки и статьи и выложу в ВИКИ
Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: Denjs от Сентябрь 14, 2009, 00:51 ок... нашел требования... на днях как доберутся руки - сделаю..
Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: merke от Январь 26, 2011, 14:07 Но всё же, как считать stdin в Qt приложении?
Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: Denjs от Январь 26, 2011, 14:46 Но всё же, как считать stdin в Qt приложении? гм... o_O как написано в классе - Код: QFile stdIn; Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: merke от Январь 26, 2011, 18:35 К примеру делаю вот так:
Код
Гуй напрочь зависает, а если взять и закрыть родительский процесс гуй у дочернего отмирает и выводится то чтобы было в stdin Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: merke от Январь 26, 2011, 19:12 Посмотрите пожалуйста, вот этот код. Ну ни чего не работает(((
Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: lit-uriy от Январь 26, 2011, 19:56 >>data = stdIn.readAll();
вот он и читает до посинения. Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: Denjs от Январь 26, 2011, 20:31 Александр, я вижу ваше недовольство/недоумение. я вижу ваш код.
но я не вижу чем именно вы недовольны, и какое поведение программы вы видите правильным? например сейчас, я могу п едложить вам в родительской программе закрывать файл, который перенаправляется в дочерний stdin) но чувствуется мне - это не то что хотите. опишите идеальное я вас поведение и задачи/цели/среду применения? --------------------- readAll() скорее всего не работает, по тем-же причинам, что и описаны в пунктах 1 и 2 в "3 ключевых "пунктега" касающихся чтения stdin через QFile ". пока не прочитан хоть один байт - вы не сможете понять сколько там у вас данных. и "зависните в операции чтения", если данных нет. Ещё раз обратите внимание на ту часть исходного кода, которая ... Код: data=stdIn.read(1); //тут "блокирующее чтение"... потому никаких sleep не надо потому предлагаю дописать вам в исходный класс буфер, и функцию readAll() для данного класса. Включая byteaAvalable(). Но помните что тут вы имеете дело с потоками, а QByteArray очень не любит когда к нему из 2-х потоков обращаются. потому смотрите ещё и что такое мьютексы. и работайте с входным потоком через этот класс. --------------------- лучше расскажите зачем и в какой ситуции вы хотите это использовать, Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: merke от Январь 27, 2011, 08:36 В общем рассказываю всю историю. Имеется допустим два приложения. Одно сервисное, оно запускает второе приложение и они должны между собой общаться служебными командами. В первой версии общение происходило по сокетам, далее решено было перевести всё на Pipe, но и эту идею исключили, в конечном случае остановились на использовании stdin/stdout/stderr. С дочернего процесса я спокойно пишу в stdin & stderr. В родительском я запросто всё это отлавливаю посредством сигналов класса QProcess. А вот уже прочитать stdin в дочернем приложении я и не могу.
Идея следующая: будет таймер с интервалом примерно 5 секунд. В обработчике таймера будет проверяться на наличие данных в stdin. Если такие имеются считывать их, определять что за команда нам поступила от сервисного приложения и производить определенные действия. На момент пока производятся эти самые "определенные действия", таймер будет останавливаться, а после их выполнения таймер будет заново перезапускаться. Так вот, если в обработчике таймера писать следующий код: Код
Всё к едрени фени зависает. Ни что не могу понять... Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: Denjs от Январь 27, 2011, 11:47 Всё к едрени фени зависает. Ни что не могу понять... Прально, зависает до следующей порции данных )) вы де перечитали пост стартующий тему и понимаете что чтение с стдина - "блокирующее", что означает что мы повиснем пока не получим данных?вы думаете почему я это все поместил в отдельный поток внутри QThread ?! что бы оно там себе висло до поступления следующей порции данных или закрытия канала - и никому это не мешало. почему вы упорно не хотите просто взять и использовать класс представленный в начале топика? принимайте сигналы им генерируемые, буферизируйте их, и каждые 5 секунд по вашему таймеру смотрите что там у вас есть в вашем входном буфере - и будет вам счастье. Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: merke от Январь 27, 2011, 18:00 Спасибо!!!
Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: asvil от Июнь 30, 2011, 18:30 О кстати, здесь то можно использовать QSocketNotifier примерное вот так:
Код: class Receiver : public QObject Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: asvil от Июль 25, 2011, 13:36 :( Под винду socketnotifier не работает
Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: navrocky от Август 17, 2012, 19:01 Ну вот. И я столкнулся с этой проблемой.
Глянул одним глазом приведенный выше класс. Мне кажется, но эмитить так просто сигналы из потока нельзя. Надо сделать вложенный объект. Сейчас запилю доработанный класс, выложу в нашу копилку.. Upd. Только сейчас понял, что не существует способа остановить читающий поток, т.к. невозможно пробудить заблокированный read... :-[ Хм. Всё плохо. Видимо надо браться за системные вызовы и писать платформозависимый код... Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: andrew.k от Август 25, 2012, 23:25 А чем не устраивают сигналы от QProcess и соответствующие функции чтения?
Код
Название: Re: как читать STDIN в сигнал-слотовом стиле? ответы здесь. Отправлено: navrocky от Август 31, 2012, 18:19 Имеется ввиду чтение своего потока stdin, а не чтение из дочернего процесса.
|