我正在Python中运行tcpdump
,我想知道内核丢弃了多少数据包。
当在命令行上运行时,tcpdump看起来像这样:
me@mypc:$ sudo tcpdump -w myPackets.cap -i eth0 ip
tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes
^C28 packets captured
28 packets received by filter
0 packets dropped by kernel
这就是我在Python脚本中调用tcpdump
的方式:
f_out = open("tcpdumpSTDOUT", "w")
f_err = open("tcpdumpSTDERR", "w")
tcpdumpProcess = subprocess.Popen(['tcpdump',
'-w', 'myPackets.cap', '-i', 'eth0', '-n','ip'],
stdout=f_out,
stderr=f_err)
# a few seconds later:
tcpdumpProcess.kill()
f_in.close()
f_out.close()
现在,如果我看tcpdumpSTDERR
,我只看到通常输出行中的第一行:
tcpdump:在eth0上侦听,链路类型EN10MB(以太网),捕获大小65535字节
剩下的都在哪里?
编辑我尝试了一种不同的方法:
>>> myProcess = subprocess.Popen("tcpdump -w myPackets.cap -i eth2 ip", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> myProcess.communicate()
然后我从另一个shell中杀死了tcpdump,commnunitate()的输出显示为:
('', 'tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytesn')
仍然只是第一行!
编辑2有趣的是:
>>> import shlex
>>> a = subprocess.Popen(shlex.split("tcpdump -w myPackets.cap -i eth2 ip"), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> a.terminate()
>>> a.communicate()
('', 'tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytesn221 packets capturedn221 packets received by filtern0 packets dropped by kerneln')
使用proc.terminate()
而不是proc.kill()
:
import shlex
import subprocess
import time
with open("tcpdumpSTDERR", "wb") as f_err: # close the file automatically
proc = subprocess.Popen(shlex.split("tcpdump -w myPackets.cap -i eth2 ip"),
stderr=f_err)
time.sleep(2) # wait a few seconds
proc.terminate() # send SIGTERM instead of SIGKILL
proc.wait() # avoid zombies
问题是我在进程上调用了kill()
而不是terminate()
。对于后者,所有消息都存储在我指定的stderr
中(出于某种原因,tcpdump写入stderr,而不是stdout)。
因此,为了避免对其他人有所帮助,我决定将stderr重定向到subprocess.PIPE
,并直接用Python:解析字符串
>>> tcpdumpProcess = subprocess.Popen(['tcpdump',
'-w', 'myPackets.cap', '-i', 'eth0', '-n','ip'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
>>> tcpdumpProcess.terminate()
# stdout in [0], stderr in [1]
>>> tcpdump_stderr = tcpdumpProcess.communicate()[1]
>>> print tcpdump_stderr
tcpdump: listening on eth2, link-type EN10MB (Ethernet), capture size 65535 bytes
40 packets captured
40 packets received by filter
0 packets dropped by kernel