LINUX.ORG.RU

Помогите с PIPE

 , ,


0

1

Привет всем!

Если создать анонимное соединение PIPE (c помощью pipe + Fork + execl…):

Это псевдокод (просто для информации) , так что не пинайте пожалуйста:

pipe(&iReadPipe);
pipe(&iWritePipe);
pid = fork()
If (pid == 0) {
	close(iWritePipe[1]);
	close(iReadPipe[0]);
	dup2(iWritePipe[0], STDIN_FILENO);
	close(iWritePipe(0));
	dup2(iReadPipe[1], STDOUT_FILENO);
	close(iReadPipe[1]);
	execl(szCmd, szCmd, NULL);
}	
if pid > 0 {
	pIn = fdopen(iReadPipe[0], "r");
	pOut = fdopen(iWritePipe[1], "w"); 
	setvbuf(pIn, NULL, _IONBF, 0);
	setvbuf(pOut, NULL, _IONBF, 0);
}

то текстовые сообщения можно отправлять и принимать между процессами.

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

Мне нужно:

дочерний процесс ждет ожидания какой-то клавиши или вводимого текста с клавиатуры. Родительский процесс должен послать нажатия клавиш дочернему процессу и дочерний мог принять.

Именованные PIPE мне не подходят , поскольку приложение с которым будет устанавливаться связь является сторонним.

Подскажите как правильно сделать.



Последнее исправление: xpqpx (всего исправлений: 2)

Если проблема в том, что запускаемая в чайлде программа проверяет, что stdin является терминалом, попробуй использовать forkpty вместо fork.

iliyap ★★★★★
()
Ответ на: комментарий от iliyap

Нет , проблема не в этом.

Проблема в том, что любой ожидающий ввод клавиши в дочернем процессе , замораживает PIPE

xpqpx
() автор топика

Подскажите как правильно сделать.

Что ж Вы как маленький - натравите strace -f на ls | less и Вы сразу поймёте какие syscalls нужны.

bugfixer ★★★★★
()
Ответ на: комментарий от xpqpx

Он не может замораживать pipe.

Может происходить другое, что ты мог перепутать с этим: дочерний процесс ждёт клавиатуру, и пока он её ждёт - он не читает pipe (конечно же, дочерний процесс совсем не обязательно так будет делать, но вполне может оказаться, что делает он именно так). Родительский процесс пишет что-то в pipe, дочерний - не читает, а буфер у пайпа не бесконечный (по дефолту - довольно маленький, гораздо меньше чем у tcp/ip коннектов), он заканчивается, и после этого родительский процесс начинает ждать пока в нём освободится место. Освободиться оно может только если дочерний что-то прочтёт, а он читать не хочет. Решение: переделать дочерний процесс, чтобы во время ожидания клавиатуры проверял и пайпы тоже.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Решение: переделать дочерний процесс, чтобы во время ожидания клавиатуры проверял и пайпы тоже.

ТС вроде как писал что:

приложение с которым будет устанавливаться связь является сторонним

Мне даже интересно стало как именно «дочерний процесс ждёт клавиатуру», и как его можно обмануть чтобы он думал что у него tty, а для parent’а это был pipe. Будем следить за развитием событий :)

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

А, тфу, я думал что клавиатура и пайп это разные сущности (не внимательно читал вопрос). А тут речь всего лишь про перенаправленный stdin/stdout. Думаю tty тут ни при чём, хотя если дело и правда в нём то поднять pty вместо пайпов хоть и сложнее но не сильно (выглядеть будет почти как пайп, но все проверки на «это терминал» пройдёт).

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

Мой первый ответ не читай, я там неправильно понял суть ситуации. Объясни подробнее, что у тебя происходит.

невозможно производить ввод\вывод по трубам

Что значит «невозможно»? Зависает write()? Или зависает read()? Или оба? Или ошибки (какие?) отдают?

Попытка вводить что-то в терминал бесполезна , похоже блокируется любое действие по трубам.

Как вводить? Речь про запись в пайп из родительского процесса или про реальную клавиатуру?

pipe(&iReadPipe);
pipe(&iWritePipe);

Я конечно понимаю что это псевдокод, но как объявлено iReadPipe? Должно быть int iReadPipe[2] и без всяких &.

Коды ошибок от pipe() и от dup2() почему не проверяешь? Или это опять особенность псевдокода? Примерно так хотя бы:

if(pipe(iReadPipe)<0) { fprintf(stderr,"pipe(iReadPipe) error %d (%s)\n", errno, strerror(errno)); exit(-1); }
if(pipe(iWritePipe)<0) { fprintf(stderr,"pipe(iWritePipe) error %d (%s)\n", errno, strerror(errno)); exit(-1); }
if(dup2(iWritePipe[0], STDIN_FILENO)<0) { fprintf(stderr,"dup2(,0) error %d (%s)\n", errno, strerror(errno)); exit(-1); }

А ещё iReadPipe[] и iWritePipe[] могут содержать дескрипторы 0 и 1, если они раньше были закрыты, тогда логика dup2() и close() в чайлде может сломаться.

firkax ★★★★★
()

Как любил говорить профессор Преображенский: разруха в головах. Прежде всего необходимо пройти ликбез, хотя бы тут: https://www.opennet.ru/docs/RUS/lpg/node6.html и тогда такие вопросы отпадут сами собой.

anonymous
()
Ответ на: комментарий от bugfixer

Чтобы процесс думал, что у него терминал, его и нужно запускать в псевдотерминале (pty), как ssh, screen, expect и пр. делают.

Если же процесс вобще лезет к /dev/input/event, то, разве что по аналогии с reptyr посредством ptrace заставлять его открыть другой файл. Но у процесса может быть от этого защита...

mky ★★★★★
()
Ответ на: комментарий от firkax

Все ошибки , что вы описали - это особенность псевдокода. Просто я пишу не на СИ , поэтому и кажется , что в псевдокоде много ошибок. В реальном коде глупых ошибок нет и все проверки соблюдены. Псевдокод наваял быстренько просто , чтобы была понятна схема подключения.

дочерний процесс ждёт клавиатуру, и пока он её ждёт - он не читает pipe

Скорее всего в этом и есть причина. Сейчас я загрузил несколько программ , использующих PIPE , пытаюсь анализировать.

Как любил говорить профессор Преображенский: разруха в головах. Прежде всего необходимо пройти ликбез, хотя бы тут: https://www.opennet.ru/docs/RUS/lpg/node6.html и тогда такие вопросы отпадут сами собой.

За ссылку спасибо , тем более за русский вариант.

xpqpx
() автор топика
Ответ на: комментарий от xpqpx

Спасибо всем за ответы. Попробовал создать CHILD с функцией SCANF и с ним нет проблем. Видать все таки дочерний процесс как-то по хитрому устроен. Попробую еще раз все проанализировать. Буду временно неактивен.

xpqpx
() автор топика

Такое впечатление, что надо переходить на асинхронное взаимодействие с пайпами, чтобы не виснуть при переполнении буфера.

xaizek ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.