在使用Popen模块创建进程执行时,发现启动的进程proc在使用proc.kill()后,仍然存在。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import time
from subprocess import Popen, PIPE

# airodumpProc = Popen(["/usr/local/sbin/airodump-ng", "wlan0"])
airodumpProc = Popen("/usr/local/sbin/airodump-ng wlan0", shell = True)

time.sleep(10)
airodumpProc.kill()

while True:
    time.sleep(3)

例如上面的代码,使用Popen模块运行airodump-ng程序扫描周边的Wifi。程序启动后会在主进程下生成好几个子孙进程。

经过10秒后杀死进程,对应主进程下的子孙进程消失,但是并没有真正的消失。

处理前:

Popen_shell_process_htop

处理后:

Popen_shell_kill_process_1

Popen_shell_kill_process_2

可以使用pgrep airodump-ng -a命令看见,之前执行任务的子孙进程仍在运行中,不过在主进程中的状态已经不存在。只有当关闭执行程序时,相关进程才会退出。

Popen_shell_watch_process_1

使用os.kill(pid, sig)命令同样杀不死。之前一直使用的是pkill airodump-ng的方式杀死所有同名的进程,现在有的需求是,需要保留其余同名的进程,而只让目标进程及其子孙进程停止工作。

Google了一下,发现提供的方法大多是os.killpg()的方式,但这种方式会杀死进程所属的组进程,导致程序退出,显然无法满足现在的需要。

其他方法也试了,都无法解决实际问题。

现在找到的方法比较笨,找到主进程下所有的子孙进程,一个个杀死,再杀死主进程。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import time
import os
import signal
import psutil
from subprocess import Popen, PIPE


def KillProcByPid(pid):
    """
    根据进程id杀死对应进程下的所有进程,包括子进程
    :param pid: 进程ID
    :return:
    """
    proc = psutil.Process(pid)
    childProc = proc.children(recursive = True)
    for p in childProc:
        os.kill(p.pid, signal.SIGKILL)
    os.kill(pid, signal.SIGKILL)


# airodumpProc = Popen(["/usr/local/sbin/airodump-ng", "wlan0"])
airodumpProc = Popen("/usr/local/sbin/airodump-ng wlan0", shell = True)

time.sleep(10)
# airodumpProc.kill()
KillProcByPid(airodumpProc.pid)

while True:
    time.sleep(3)

使用psutil.Process(pid)方法,附着目标进程,获取目标进程下的所有子孙进程,参数recursive = True表示的是获取子孙进程。

获取子孙进程后,得到子孙进程的pid,根据pid,一个个杀死子孙进程,最后结束主进程。

进程此番处理后,目标主进程下的子孙进程就都处理完毕了。

处理前:

Popen_shell_process2

处理后:

Popen_shell_watch_process_2