Взаимодействие подпроцессов Python, почему мой процесс работает с Popen.communicate, но не с Popen.stdout.read()?

Я пытаюсь общаться с чат-ботом командной строки с Python, используя модуль subprocess. (http://howie.sourceforge.net/ с использованием скомпилированного двоичного файла win32, у меня есть свои причины!)

Это работает:

proc = Popen('Howie/howie.exe', stdout=PIPE,stderr=STDOUT,stdin=PIPE)
output = proc.communicate()

Но Popen.communicate ждет завершения процесса (и отправляет ему EOF?), я хочу иметь возможность взаимодействовать с ним. Очевидное решение для этого состояло в том, чтобы читать stdout / писать stdin следующим образом:

Это не работает:

proc = Popen('Howie/howie.exe', stdout=PIPE,stderr=STDOUT,stdin=PIPE)
while True: print proc.stdout.readline()

(Обратите внимание, что на самом деле я использую более сложный код, основанный на http://code.activestate.com/recipes/440554/ но проблема та же.)

Проблема в том, что второй подход отлично работает для связи с cmd, но когда я запускаю чат-бота, ничего. Итак, мой вопрос: чем это отличается при захвате вывода от использования Popen.communicate()?

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


person SudoNhim    schedule 12.03.2012    source источник


Ответы (2)


Одно из основных различий между ними заключается в том, что функция communit() закрывает стандартный ввод после отправки данных. Я не знаю о вашем конкретном случае, но во многих случаях это означает, что если процесс ожидает окончания пользовательского ввода, он получит его, когда используется коммуникация (), и никогда не получит его, когда код блокируется на read() или readline().

Попробуйте сначала добавить Popen.stdin.close() и посмотрите, повлияет ли это на ваш случай.

person vmalloc    schedule 12.03.2012
comment
Почему, спасибо, закрытие стандартного ввода позволило чат-боту запуститься точно так же, как Popen.communicate, хотя теперь у меня проблема, что мне нужно продолжать общаться с ним... - person SudoNhim; 13.03.2012
comment
Возможно, ваше приложение читает строку за строкой, и в этом случае вы можете просто отправить отдельные строки, чтобы оно ответило? Какую именно задачу вы пытаетесь выполнить? - person vmalloc; 13.03.2012
comment
Но как я могу отправить его после закрытия стандартного входа? Я хочу иметь возможность отправлять и получать построчно - person SudoNhim; 13.03.2012
comment
@SudoNhim: рассмотрите возможность использования pexpect вместо subprocess, если вам нужна двусторонняя связь с процессом. - person Fred Foo; 13.03.2012
comment
Спасибо, я посмотрю на это. Просто нашел возможное решение; отправка символа EOF вручную ('\x1a' в Python) имеет тот же эффект для программы, что и стандартный ввод, за исключением, конечно, того, что он оставляет стандартный ввод открытым. Однако программа по-прежнему выдает фиктивный символ EOF. - person SudoNhim; 13.03.2012

Если вы хотите взаимодействовать с программой после отправки EOF, а не использовать Popen.stdin.close(), вы можете вручную отправить символ конца файла из командной строки, который имеет тот же эффект, но оставляет стандартный ввод открытым.

В Python escape-последовательность этого символа — '\x1a'.

person SudoNhim    schedule 16.03.2012
comment
Это работает только в странном мире DOS/Windows, которые используют фиксированный ^Z в качестве маркера EOF. Во многих других системах вместо этого обычно используется ^D (\x04), однако его можно легко изменить, и на него не следует полагаться, и определенно никогда нигде жестко не закодирован. - person ravilov; 15.07.2019