c – 子进程的异步双向IO重定向
我试图找出子进程的异步双向IO重定向的通用方法.基本上,我想生成一个等待输入的交互式子进程,应该回读任何输出.我尝试通过生成一个新的
python进程来试验
python.subprocess.试图实现的基本简化示例如下
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插座,但为此我必须改变儿童过程,这可能是不可行的.有没有其他方法可以实现它? 注意***我的最终目标是创建一个可以与远程Web客户端交互的服务器REPL过程.虽然给出的示例是Python,但我的最终目标是通过通用包装器包装所有可用的REPL. 在答案的一些建议的帮助下,我想出了以下内容 #!/usr/bin/python import subprocess,os,select proc = subprocess.Popen(['/usr/bin/python'],stdout=subprocess.PIPE,stderr=subprocess.PIPE) for i in xrange(0,5): inputready,outputready,exceptready = select.select([proc.stdout,proc.stderr],[proc.stdout,0) if not inputready: print "No Data",print inputready,exceptready for s in inputready: print s.fileno(),s.readline() proc.terminate() print "After Terminating" for i in xrange(0,s.readline() 现在,虽然程序没有陷入僵局,但不幸的是没有输出.运行上面的代码我得到了 No Data [] [] [] No Data [] [] [] No Data [] [] [] No Data [] [] [] No Data [] [] [] After Terminating No Data [] [] [] No Data [] [] [] No Data [] [] [] No Data [] [] [] No Data [] [] [] 仅供参考, /usr/bin/python 2>&1|tee test.out 似乎工作得很好. 我还想出了一个’C’代码.但结果并没有什么不同. 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,&tv); return FD_ISSET(STDIN_FILENO,&fds); } void receive(char *str) { char ch; fprintf(stderr,"IN1n"); if(!kbhit()) return; fprintf(stderr,"IN2n"); fprintf(stderr,"%dn",kbhit()); for(;kbhit() && (ch=fgetc(stdin))!=EOF;) { fprintf(stderr,"%c,%d",ch,kbhit()); } fprintf(stderr,"Donen"); } 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 valuen",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,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; } 解决方法
在您发布的Python代码中,您没有使用正确的流:
inputready,exceptready = select.select( [proc.stdout,# read list [proc.stdout,# write list [proc.stdout,# error list. 0) # time out. 我没有尝试修复它,但我打赌阅读和写入同一组流是不正确的. 您的样本中有多个问题.第一个是你作为子进程启动的python可执行文件不产生输出.第二个是存在竞争条件,因为您可以在子进程生成输出之前连续5次调用select(),在这种情况下,您将在读取任何内容之前终止该进程. 我解决了上面提到的三个问题(写清单,启动产生输出和竞争条件的过程).试试这个样本,看看它是否适合你: #!/usr/bin/python import subprocess,select,time path = "/usr/bin/python" proc = subprocess.Popen([path,"foo.py"],5): time.sleep(1) inputready,exceptready = select.select( [proc.stdout,[proc.stdin,],proc.stderr,proc.stdin],0) if not inputready: print "No Data",exceptready for s in inputready: print s.fileno(),s.readline() proc.terminate() print "After Terminating" for i in xrange(0,s.readline() 我使用的foo.py文件包含: #!/usr/bin/python print "Hello,world!" 以下版本(主要删除了冗余输出以使结果更易于阅读): #!/usr/bin/python import subprocess,0) for s in inputready: line = s.readline() if line: print s.fileno(),line proc.terminate() print "After Terminating" for i in xrange(0,line 给出以下输出:
请注意,由于某些原因,在select.select()中使用timeout参数并未在我的系统上产生预期的结果,而是使用time.sleep()代替.
你不能得到这种效果,因为这个例子仍然给python解释器一个控制tty.没有控制tty,python解释器不会打印Python版本,也不会显示>>>提示. 一个接近的例子如下.您可以将/ dev / null替换为包含要发送到解释器的命令的文件. /usr/bin/python </dev/null 2>&1|tee test.out 如果您将控制tty(键盘)以外的任何内容重定向到进程的标准输入,则不会从python解释器获得任何输出.这就是您的代码似乎不起作用的原因. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |