You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何终止Python中通过sudo启动的subprocess子进程(例如tcpdump)

问题根因

  1. 你调用pr.terminate()时实际是给sudo父进程发送SIGTERM信号,sudo的默认安全策略会拦截普通用户发送的SIGTERM、SIGKILL信号,所以会抛出PermissionError报错,你也没有权限直接终止root身份运行的tcpdump子进程。
  2. 终端下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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 21:57:01