Python 子流程模块是一个功能强大的库,用于启动和与子流程交互。它附带了一些高级 api,比如调用、检查输出和(从 Python 3.7开始)运行,这些都集中在的程序运行和等待完成的子进程上。
在这篇文章中,想讨论这个任务的一个变体,它不太直接涉及一个长时间运行的子进程。考虑测试一些服务器——例如 HTTP 服务器。将它作为一个子进程启动,然后将客户机连接到它,并运行一些测试序列。当完成后,希望以一种有序的方式关闭儿童程序。这对于同步运行子进程的 api 来说是很难实现的,因此必须查看一些较低级别的 api。
最近做的项目安卓 shell 里面有些就需要这个。
当然,可以使用 subprocess.run在一个线程中启动一个子进程,并在另一个线程中与其交互(例如,通过一个已知的端口, 比如HTTPServer)。但是,当完成了子进程之后,要完全终止它将变得非常棘手。如果子进程有一个有序的终止序列(比如发送某种“退出”命令) ,那么这是可行的。但是大多数服务器不这样做,只会永远旋转直到死亡。这就是这篇文章所讨论的用例。
启动,交互,终止,并获得所有输出时完成
第一个最简单的用例是启动一个 HTTP 服务器,与它交互,干净利落地终止它,并在完成后获取所有服务器的 stdout 和 stderr。下面是这些代码的重要部分(本文的所有代码示例都可以在这里找到) ,用 Python 3.6进行了测试:
defmain():proc=subprocess.Popen(['python3','-u','-m','http.server','8070'],stdout=subprocess.PIPE,stderr=subprocess.STDOUT)try:time.sleep(0.2)resp=urllib.request.urlopen('http://localhost:8070')assertb'Directory listing'inresp.read()finally:proc.terminate()try:outs,_=proc.communicate(timeout=0.2)pr