![](/img/trans.png)
[英]Appropriate closing of asyncio process without leaving it in zombie state
[英]How to double fork from a Python web server without leaving a zombie process?
Python 3.6
我有一个简单的Python Web服务器,当它收到POST请求时,会产生一个netcat进程来监听端口。
似乎工作正常,除了在产卵后留下一个僵尸。
(下面的服务器代码)
我向服务器发送POST请求,如下所示:
curl -X POST -H "Content-Type: text/plain" --data "example data" localhost:8000
之后,我做了一个ps ax,看看进程正在运行,netcat进程在那里,Web服务器在那里,还有一个僵尸。
6873 pts/0 S+ 0:00 python3 nc_server.py
6876 ? Zs 0:00 [python3] <defunct>
6877 ? S 0:00 nc -l 54927
为什么? 我怎么能避免僵尸?
from http.server import HTTPServer, BaseHTTPRequestHandler
import socket
import os
import io
host = '0.0.0.0'
port = 8000
def find_free_port():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 0))
return s.getsockname()[1]
def spawn_netcat(port):
command = "/bin/nc"
params = f"nc -l {port}"
spawnDaemon(command, params.split())
def spawnDaemon(path_to_executable, params):
# Do first fork
pid = os.fork()
if (pid != 0):
return
# Decouple from parent environment
os.chdir("/opt")
os.setsid()
os.umask(0)
# Do second fork
pid = os.fork()
if (pid != 0):
os._exit(0)
# exec this process into netcat.....
os.execv(path_to_executable, params)
class Server(BaseHTTPRequestHandler):
def do_POST(self):
netcat_listen_port = find_free_port()
spawn_netcat(netcat_listen_port)
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
response = io.BytesIO()
response.write(str(netcat_listen_port).encode())
self.wfile.write(response.getvalue())
if __name__ == "__main__":
httpd = HTTPServer((host, port), Server)
httpd.serve_forever()
当进程终止时,它期望其父代收集其返回代码。 在此之前,它就位于亡灵(僵尸)中,它不再运行,但它无法从进程表中清除。 如果父进程不再存在,则进程将重新成为init(或至少某些已启用systemd的系统IIRC上的专用reaper进程)。 在您的进程列表中,您将看到第一个fork的子级,其中包含其父级,但未收集返回状态。
长话短说,经过第一个fork()
,你可以在父进程return
之前插入它:
os.waitid(os.P_PID, pid, os.WEXITED)
即:
# Do first fork
pid = os.fork()
if (pid != 0):
os.waitid(os.P_PID, pid, os.WEXITED)
return
这个孩子只是短暂的并且退出。 在返回函数之前,它会等待它执行此操作。 在这种情况下应该没问题。 否则,一般情况下,如果您的进程产生可能在以后退出的子进程,那么您将注册一个SIGCHLD
处理程序来处理此问题。 即使除了双叉到daemonize之外,你通常会使用Popen并使用子进程与你的进程接口。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.