Python:在运行子进程时处理中断



我为 tcpdump 编写了一个简单的 Python 解析器。这个想法是连续运行 tcpdump 作为子进程,解析其输出并在用户请求时输出基本报告(通过 Ctrl-Z 中断(,而无需停止脚本。

Ctrl-C 还应该输出报告并完全退出脚本,这行得通。

问题是当我按 Ctrl-Z 时,中断处理程序被调用,它按预期输出tcpdump_output,但随后脚本停止处理 tcpdump 子进程的输出,即使它仍在后台运行(我用 ps 检查(。

脚本的简化版本:

#!/usr/bin/env python
import subprocess as sub
import socket
import signal
import sys
tcpdump_output = ""
def signal_handler(sig, frame):
print('nInterrupt detected. Output:')
print(tcpdump_output)
if(sig is signal.SIGINT):
print('Terminated.')
sys.exit(0)

def process_tcpdump_line(line):
print("processing tcpdump line: " + line)
global tcpdump_output
tcpdump_output += line + "n"

# get host ip address
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
local_ip = s.getsockname()[0]
s.close()
# register interrupt handlers
signal.signal(signal.SIGINT, signal_handler)    # Handle Ctrl-C
signal.signal(signal.SIGTSTP, signal_handler)   # Handle Ctrl-Z

# prepare tcpdump command
dst = 'dst host ' + local_ip
p = sub.Popen(('sudo', 'tcpdump', '-nqnn', '-l', dst), stdout=sub.PIPE)

# process tcpdump output
for row in iter(p.stdout.readline, b''):
process_tcpdump_line(row.strip())
print("this is never reached.")

我尝试将 for 循环包装在while True但在调试时我发现它没有区别,最后一行实际上从未到达。

所以似乎在处理中断之后,脚本挂在p.stdout.readline上。

有没有办法在不影响子进程的情况下处理中断,或以其他方式恢复其处理?

如果检查ps aux输出,您将看到 tcpdump 进程的STAT列在按 Ctrl+Z 后发生更改:

在 CTRL+Z 之前:

USER              PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root            15064   0.0  0.0  2463988   1096 s010  S+    4:40PM   0:00.01 tcpdump -nqnn -l dst host 192.168.1.169
root            15063   0.0  0.0  2461648   2004 s010  S+    4:40PM   0:00.01 sudo tcpdump -nqnn -l dst host 192.168.1.169
nickolay        15062   0.0  0.0  2432140   7136 s010  S+    4:40PM   0:00.04 /opt/local/Library/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python tcpd.py

在 Ctrl+Z 之后:

USER              PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root            15064   0.0  0.0  2463988   1096 s010  T+    4:40PM   0:00.01 tcpdump -nqnn -l dst host 192.168.1.169
root            15063   0.0  0.0  2461648   2004 s010  T+    4:40PM   0:00.01 sudo tcpdump -nqnn -l dst host 192.168.1.169
nickolay        15062   0.0  0.0  2432140   7212 s010  S+    4:40PM   0:00.04 /opt/local/Library/Frameworks/Python.framework/Ver

T状态表示"停止,无论是通过作业控制信号还是因为它正在被跟踪"。

所以问题是子进程也处理 CTRL+Z 并且"被作业控制停止"。

若要避免这种情况,请忽略子进程中的信号:

p = sub.Popen(('sudo', 'tcpdump', '-nqnn', '-l', dst), stdout=sub.PIPE,
preexec_fn = lambda: signal.signal(signal.SIGTSTP, signal.SIG_IGN))

最新更新