程序一:未使用信号处理程序
#! /usr/bin/python
import socket, os
"""
简单网络程序,每次连接后派生的子进程终止后都会成为僵死进程
"""
serSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serSock.bind(("", 8888))
serSock.listen(5)
while True:
conn, addr = serSock.accept()
pid = os.fork()
if pid:
"""
父进程关闭子进程的已连接套接字
"""
conn.close()
continue
elif pid == 0:
"""
子进程关闭父进程的监听套接字
"""
serSock.close()
data = conn.recv(1024)
conn.sendall("echo: "+data)
conn.close()
os._exit(0)
上图明显可见父进程的几个僵死子进程
程序二:使用信号处理程序
#! /usr/bin/python
import signal, socket, os
"""
信号处理函数,waitpid获取终止子进程的某些信息,但这里我们不关注,所以未定义返回值
"""
def signal_handler(num):
while not (waitpid(-1, os.WNOHANG)):
return
"""
安装信号处理函数
"""
signal.signal(signal.SIGCHLD, signal_handler)
"""signal.signal(signal.SIGCHD, signal_handler)"""
"""
某些会阻塞的系统调用会被在信号处理程序返回后被中断,这里处于各个平台的兼容性考虑,我们手动重启被中断的系统调用
"""
signal.siginterrupt(signal.SIGCHLD, False)
"""signal.siginterrupt(signal.SIGCHD, False)"""
serSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serSock.bind(("", 8888))
serSock.listen(5)
while True:
conn, addr = serSock.accept()
pid = os.fork()
if pid:
conn.close()
continue
elif pid == 0:
serSock.close()
data = conn.recv(1024)
conn.sendall("echo: "+data)
conn.close()
os._exit(0)
程序三:使用multiprocessing.Processing代替os.fork
#! /usr/bin/python
import multiprocessing, socket, time
def handler(conn, serSock):
serSock.close()
data = conn.recv(1024)
conn.sendall("echo: " + data)
serSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serSock.bind(("", 9999))
serSock.listen(5)
while True:
conn, addr = serSock.accept()
childProcess = multiprocessing.Process(target=handler, args=(conn, serSock))
childProcess.start()
conn.close()
开启三个客户端与服务器相连,截图如下:
可以明显看到三个派生的子进程
现在依次断开三个客户端的连接,使得派生子进程终止,截图如下:
这里出现第一个僵死进程
这里出现第二个僵死进程
这里出现第三个僵死进程
再建立一次连接:
发现原先的僵死进程被清除了 不过这次连接断开后仍然会出现一次僵死进程 不过阀体可以知道multiprocessing.Process自行处理僵死进程,不用想os.fork那样自己建立信号处理程序、安装信号处理程序