如何终止Python中通过sudo启动的subprocess子进程(例如tcpdump)
问题根因
- 你调用
pr.terminate()时实际是给sudo父进程发送SIGTERM信号,sudo的默认安全策略会拦截普通用户发送的SIGTERM、SIGKILL信号,所以会抛出PermissionError报错,你也没有权限直接终止root身份运行的tcpdump子进程。 - 终端下CTRL+C能生效的原因是它会向整个前台进程组发送
SIGINT信号,sudo默认允许转发这类终端交互信号给子进程,tcpdump接收到SIGINT后会正常退出,sudo进程也会随之结束。
可行解决方案
方案1:发送SIGINT信号(等效CTRL+C)
直接替换pr.terminate()为发送SIGINT信号即可,不需要额外改启动逻辑:
import signal # ... 原有启动逻辑不变 for pr in self.acquisitions: if pr.poll() is None: # 替换原有pr.terminate()调用 pr.send_signal(signal.SIGINT) # 可选添加等待逻辑,避免残留僵尸进程 pr.wait(timeout=3) # ... 后续逻辑不变
方案2:通过sudo kill终止进程
如果你的当前用户配置了无密码sudo权限,可以直接调用sudo kill终止对应进程:
import subprocess for pr in self.acquisitions: if pr.poll() is None: # 调用sudo kill杀掉sudo进程,会自动终止其子进程tcpdump subprocess.run(['sudo', 'kill', str(pr.pid)], check=True) pr.wait()
如果存在多个tcpdump进程需要批量清理,也可以用subprocess.run(['sudo', 'pkill', '-f', 'tcpdump.*7943'])精准匹配要杀的进程,避免误杀。
方案3:指定进程组发送信号
如果前两个方案不生效,可以在启动子进程时指定创建新的会话,终止时给整个进程组发信号:
import os import signal # 启动时添加start_new_session参数 pr = subprocess.Popen( ['/usr/bin/sudo', '/usr/sbin/tcpdump', '-i', 'enp7s0', 'host', adr, 'and', 'udp', 'port', '7943', '-w', fn], start_new_session=True ) self.acquisitions.append(pr) # 终止时给整个进程组发SIGINT for pr in self.acquisitions: if pr.poll() is None: os.killpg(os.getpgid(pr.pid), signal.SIGINT) pr.wait()
内容的提问来源于stack exchange,提问作者ZioByte
相关产品推荐
相关产品推荐

