python - subprocess.Popen():在子进程执行期间更改标准错误
问题描述
目标:我试图将一个 Python 脚本放在一起,以捕获由于执行代码块而发生的网络流量。为简单起见,假设我想记录调用socket.gethostbyname('example.com')
. 注意:我不能简单地tcpdump
在gethostbyname()
返回时终止,因为我想要测量的实际代码块触发了其他外部代码,而且我无法确定这个外部代码何时完成执行(所以我必须让tcpdump
运行“足够长”因为我很可能记录了此外部代码生成的所有流量)。
方法:我正在使用subprocess
to start tcpdump
,告诉在几秒钟后使用它的和选项tcpdump
终止自身,例如:duration
-G
-W
duration = 15
nif = 'en0'
pcap = 'dns.pcap'
cmd = ['tcpdump', '-G', str(duration), '-W', '1', '-i', nif, '-w', pcap]
tcpdump_proc = subprocess.Popen(cmd)
socket.gethostbyname('example.com')
time.sleep(duration + 5) # sleep longer than tcpdump is running
这样做的问题是,Popen()
return before tcpdump
完全启动并运行,因此gethostbyname()
不会捕获由调用产生的部分/全部流量。我显然可以time.sleep(x)
在调用之前添加一个gethostbyname()
来给tcpdump
一些时间来启动,但这不是一个可移植的解决方案(我不能随意选择一些x < duration
,因为一个强大的系统会比一个不太强大的系统更早地开始捕获数据包)。
为了解决这个问题,我的想法是解析tcpdump
的输出以查找何时将以下内容写入其stderr
,因为这似乎表明捕获已启动并完全运行:
tcpdump: listening on en0, link-type EN10MB (Ethernet), capture size 262144 bytes
因此我需要附加到stderr
,但问题是我不想承诺读取它的所有输出,因为我需要我的代码继续执行我想要测量的代码块(gethostbyname()
在这个例子中)而不是陷入从 读取的循环中stderr
。
我可以通过添加一个阻止主线程继续gethostbyname()
调用的信号量来解决这个问题,并且当stderr
它从stderr
如果可能的话,我想保持代码单线程。
据我了解,这是一个很大的 NONOsubprocess.PIPE
用于stderr
并且stdout
不承诺读取所有输出,因为当缓冲区填满时,孩子最终会阻塞。但是,如果您只对读取输出的第一部分感兴趣,您可以“分离”(销毁?)管道中间执行吗?本质上,我想得到这样的结果:
duration = 15
nif = 'en0'
pcap = 'dns.pcap'
cmd = ['tcpdump', '-G', str(duration), '-W', '1', '-i', nif, '-w', pcap]
tcpdump_proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, text=True)
for l in tcpdump_proc.stderr:
if 'tcpdump: listening on' in l:
break
socket.gethostbyname('example.com')
time.sleep(duration) # sleep at least as long as tcpdump is running
我还需要在块中添加什么if
来“重新分配”负责阅读的人stderr
?我可以stderr
回到None
( tcpdump_proc.stderr = None
) 吗?还是我应该打电话tcpdump_proc.stderr.close()
(tcpdump
如果我这样做会提前终止)?
也很可能是我错过了一些明显的东西,并且有更好的方法来实现我想要的 - 如果是这样,请赐教:)。
提前致谢 :)
解决方案
收到消息后,您可以在 stderr 上使用detach()
or :close()
listening on
import subprocess
import time
duration = 10
nif = 'eth0'
pcap = 'dns.pcap'
cmd = ['tcpdump', '-G', str(duration), '-W', '1', '-i', nif, '-w', pcap]
proc = subprocess.Popen(
cmd, shell=False, stderr=subprocess.PIPE, bufsize=1, text=True
)
for i, line in enumerate(proc.stderr):
print('read %d lines from stderr' % i)
if 'listening on' in line:
print('detach stderr!')
proc.stderr.detach()
break
while proc.poll() is None:
print("doing something else while tcpdump is runnning!")
time.sleep(2)
print(proc.returncode)
print(proc.stderr.read())
出去:
read 0 lines from stderr
detach stderr!
doing something else while tcpdump is runnning!
doing something else while tcpdump is runnning!
doing something else while tcpdump is runnning!
doing something else while tcpdump is runnning!
doing something else while tcpdump is runnning!
doing something else while tcpdump is runnning!
0
Traceback (most recent call last):
File "x.py", line 24, in <module>
print(proc.stderr.read())
ValueError: underlying buffer has been detached
笔记:
我还没有检查 stderr 数据到底发生了什么,但是分离 stderr 似乎对 tcpdump 没有任何影响。
推荐阅读
- c# - ObservableCollection 和 List 中的 Remove() 方法会导致大量数据出现性能问题
- javascript - 如何在reactJs中点击标题文本?
- bazel - Win 上的 Bazel 错误:命令长于 CreateProcessW 的限制(32767 个字符)
- c# - Windows 10 中的两个不同应用程序正在尝试建立与同一设备的 RFCOMM 套接字连接。如何断开一个并与另一个连接?
- blockchain - 用户费用百分比设置为零,合约执行时仍会在 tron 主网上消耗能量
- swagger - Micornaut:是否可以使用不同的端点在 Swagger OpenApi 中自定义“探索”栏?
- simics - 如何使“%bp.hap.run-until name = X86_HLT_Instr”工作?
- macos - 在 macos catalina 上安装 docker
- python - 数据库表的python内存问题
- android - NavHost 中可组合之间的 ExitAnimation