Я пытаюсь выяснить обобщенный способ для асинхронного двунаправленного ввода-вывода перенаправления дочернего процесса. В принципе, я хотел бы создать интерактивный дочерний процесс, ожидающий ввода, и любой вывод должен быть прочитан. Я попытался поэкспериментировать с python.subprocess, создав новый процесс python. Базовый упрощенный пример пытались достичь следующим образомАсинхронное двунаправленное перенаправление ввода-вывода для дочернего процесса
process = subprocess.Popen(['/usr/bin/python'],shell=False,stdin=subprocess.PIPE, stdout=subprocess.PIPE)
while True:
output = process.stdout.readline()
print output
input = sys.stdin.readline()
process.stdin.write(input)
и выполнения вышеуказанного фрагмента кода просто зависает без какого-либо вывода. Я пробовал работать с /usr/bash
и /usr/bin/irb
, но результат все тот же. Я предполагаю, что буферизованный IO просто не хорошо гелеобразован с перенаправлением IO.
Итак, мой вопрос в том, можно ли читать выходные данные дочернего процесса без промывки буфера или выхода из подпроцесса?
following post упоминает сокеты IPC, но для этого мне пришлось бы изменить дочерний процесс, который может оказаться невозможным. Есть ли другой способ его достижения?
Примечание *** Моя конечная цель - создать серверный REPL-процесс, который может взаимодействовать с удаленным веб-клиентом. Хотя приведенный пример относится к Python, моей конечной целью является завершение всего доступного REPL обобщенной оболочкой.
С помощью некоторых из предложения в ответах я придумал следующую
#!/usr/bin/python
import subprocess, os, select
proc = subprocess.Popen(['/usr/bin/python'],shell=False,stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
for i in xrange(0,5):
inputready, outputready, exceptready = select.select([proc.stdout, proc.stderr],[proc.stdout, proc.stderr],[proc.stdout, proc.stderr],0)
if not inputready: print "No Data",
print inputready, outputready, exceptready
for s in inputready: print s.fileno(),s.readline()
proc.terminate()
print "After Terminating"
for i in xrange(0,5):
inputready, outputready, exceptready = select.select([proc.stdout, proc.stderr],[proc.stdout, proc.stderr],[proc.stdout, proc.stderr],0)
if not inputready: print "No Data",
print inputready, outputready, exceptready
for s in inputready: print s.fileno(),s.readline()
сейчас, хотя эти программы не в тупик, но, к сожалению, там нет выхода. Запуск выше код я получаю
No Data [] [] []
No Data [] [] []
No Data [] [] []
No Data [] [] []
No Data [] [] []
After Terminating
No Data [] [] []
No Data [] [] []
No Data [] [] []
No Data [] [] []
No Data [] [] []
Просто FYI, работает питона, как
/usr/bin/python 2>&1|tee test.out
, кажется, работает нормально.
Я также придумал код «С». Но результат не отличается.
int kbhit() {
struct timeval tv;
fd_set fds;
tv.tv_sec = tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &fds);
}
void receive(char *str) {
char ch;
fprintf(stderr,"IN1\n");
if(!kbhit()) return;
fprintf(stderr,"IN2\n");
fprintf(stderr,"%d\n",kbhit());
for(;kbhit() && (ch=fgetc(stdin))!=EOF;) {
fprintf(stderr,"%c,%d",ch,kbhit());
}
fprintf(stderr,"Done\n");
}
int main(){
pid_t pid;
int rv, pipeP2C[2],pipeC2P[2];
pipe(pipeP2C);
pipe(pipeC2P);
pid=fork();
if(pid){
dup2(pipeP2C[1],1); /* Replace stdout with out side of the pipe */
close(pipeP2C[0]); /* Close unused side of pipe (in side) */
dup2(pipeC2P[0],0); /* Replace stdin with in side of the pipe */
close(pipeC2P[1]); /* Close unused side of pipe (out side) */
setvbuf(stdout,(char*)NULL,_IONBF,0); /* Set non-buffered output on stdout */
sleep(2);
receive("quit()\n");
wait(&rv); /* Wait for child process to end */
fprintf(stderr,"Child exited with a %d value\n",rv);
}
else{
dup2(pipeP2C[0],0); /* Replace stdin with the in side of the pipe */
close(pipeP2C[1]); /* Close unused side of pipe (out side) */
dup2(pipeC2P[1],1); /* Replace stdout with the out side of the pipe */
close(pipeC2P[0]); /* Close unused side of pipe (out side) */
setvbuf(stdout,(char*)NULL,_IONBF,0); /* Set non-buffered output on stdout */
close(2), dup2(1,2); /*Redirect stderr to stdout */
if(execl("/usr/bin/python","/usr/bin/python",NULL) == -1){
fprintf(stderr,"execl Error!");
exit(1);
}
}
return 0;
}
Как правило, вы не пытаетесь дождаться ввода и генерируете выход в реальном времени в том же потоке. – stark
@stark, Итак, вы хотите сказать, что то, что я намереваюсь достичь, невозможно сделать? Я бы просто попытался использовать [следующий пост] (http://stackoverflow.com/questions/9405985/linux-3-0-executing-child-process-with-piped-stdin-stdout), чтобы увидеть, будет ли это работать для меня или нет. – Abhijit
Если вы оба читаете и пишите из одного потока, вы можете использовать системный вызов мультиплексирования, например http://linux.die.net/man/2/poll, например. с http://docs.python.org/library/select.html –