这里的问题是您要发送SIGINT
到流程。如果您只是close
,将关闭其套接字并退出stdin
,nc
这就是您想要的。
听起来您实际上是在实际nc
程序中使用客户端(尽管不是服务器),这意味着您有两个简单的修复:
而不是lookup_client.send_signal(subprocess.signal.SIGINT)
,只是做lookup_client.stdin.close()
。nc
将在其输入中将此视为 EOF,并正常退出,此时您的服务器也将退出。
#!/usr/bin/env python
import subprocess
lookup_server = subprocess.Popen("nc -l 5050", shell=True)
lookup_client = subprocess.Popen("nc localhost 5050", shell=True, stdin=subprocess.PIPE)
print lookup_client.poll()
lookup_client.stdin.write("magic\n")
lookup_client.stdin.close()
print lookup_client.poll()
lookup_server.wait()
print "Lookup server terminated properly"
当我运行它时,最常见的输出是:
None
None
magic
Lookup server terminated properly
有时第二个None
是 a 0
,和/或它出现在之后magic
而不是之前,但除此之外,它总是四行。(我在 OS X 上运行。)
对于这个简单的案例(尽管可能不是您的真实案例),只需使用communicate
而不是尝试手动操作。
#!/usr/bin/env python
import subprocess
lookup_server = subprocess.Popen("nc -l 5050", shell=True)
lookup_client = subprocess.Popen("nc localhost 5050", shell=True, stdin=subprocess.PIPE)
print lookup_client.communicate("magic\n")
lookup_server.wait()
print "Lookup server terminated properly"
同时:
此外,如果我将 Popen 的第一个参数更改为所有这些参数的数组,则所有 nc 调用都不会正确执行,并且脚本无需等待即可运行。为什么会这样?
正如文档所说:
在 Unix 上shell=True
... 如果 args 是一个序列,则第一项指定命令字符串,并且任何附加项将被视为 shell 本身的附加参数。
所以,subprocess.Popen(["nc", "-l", "5050"], shell=True)
确实/bin/sh -c 'nc' -l 5050
,并且sh
不知道如何处理这些论点。
您可能确实想使用一个 args 数组,但是您必须摆脱shell=True
- 无论如何这是一个好主意,因为 shell 在这里没有帮助您。
还有一件事:
lookup_client.send_signal(subprocess.signal.SIGINT)
print lookup_client.poll()
这可能会打印 -2 或 None,这取决于客户端是否已完成响应SIGINT
并在您之前被杀死poll
。如果您想实际获得-2,则必须调用wait
而不是poll
(或执行其他操作,例如循环直到poll
返回非无)。
最后,为什么您的原始代码不起作用?好吧,发送SIGINT
是异步的;无法保证何时生效。举一个可能出错的例子,它可能在客户端甚至打开套接字之前生效,在这种情况下,服务器仍然坐在那里等待一个永远不会出现的客户端。
You can throw in a time.sleep(5)
before the signal
call to test this—but obviously that's not a real fix, or even an acceptable hack; it's only useful for testing the problem. What you need to do is not kill the client until it's done everything you want it to do. For complex cases, you'll need to build some mechanism to do that (e.g., reading its stdout), while for simple cases, communicate
is already everything you need (and there's no reason to kill the child in the first place).