Python 使用scapy、iftop样式计算每个IP的带宽使用率
我正在使用scapy嗅探镜像端口,并生成前10名“说话者”的列表,即使用网络上最大带宽的主机列表。我知道已经有了诸如和之类的工具,但我需要对输出进行更多的控制 以下脚本对通信量进行30秒的采样,然后以“源主机->目标主机:字节”的格式打印前10位说话者的列表。这很好,但是我如何计算每秒的平均字节数呢 我感觉将采样间隔更改为1秒不允许对流量进行良好的采样,因此似乎需要对其进行平均。所以我在脚本末尾尝试了这个: 每秒字节数=(总字节数/采样间隔) 但是产生的字节/秒似乎要低得多。例如,我以1.5 MB/s的限制速率在两台主机之间生成了一个rsync,但使用上述平均计算,我的脚本一直将这些主机之间的速率计算为200 KB/s左右……远低于我预期的1.5 MB/s。我可以通过iftop确认1.5 MB/s实际上是这两台主机之间的速率 我是否使用scapy对数据包长度进行了错误的合计(请参阅流量监视调用功能)?或者这是一个糟糕的解决方案:)Python 使用scapy、iftop样式计算每个IP的带宽使用率,python,networking,network-programming,scapy,Python,Networking,Network Programming,Scapy,我正在使用scapy嗅探镜像端口,并生成前10名“说话者”的列表,即使用网络上最大带宽的主机列表。我知道已经有了诸如和之类的工具,但我需要对输出进行更多的控制 以下脚本对通信量进行30秒的采样,然后以“源主机->目标主机:字节”的格式打印前10位说话者的列表。这很好,但是我如何计算每秒的平均字节数呢 我感觉将采样间隔更改为1秒不允许对流量进行良好的采样,因此似乎需要对其进行平均。所以我在脚本末尾尝试了这个: 每秒字节数=(总字节数/采样间隔) 但是产生的字节/秒似乎要低得多。例如,我以1.5 M
从scapy.all导入*
从集合导入defaultdict
导入套接字
从pprint导入pprint
从运算符导入itemgetter
采样间隔=30#捕获流量的时间,以秒为单位
#初始化流量指令
流量=默认DICT(列表)
#返回给定字节的人类可读单位
def人类(num):
对于x,单位为[‘字节’、‘KB’、‘MB’、‘GB’、‘TB’]:
如果num<1024.0:
返回“%3.1f%s”%(数量,x)
num/=1024.0
#处理每个数据包的回调函数
#获取每个源->目标组合的总数据包数
def流量监视器callbak(pkt):
如果IP在pkt中:
src=pkt.sprintf(“%IP.src%”)
dst=pkt.sprintf(“%IP.dst%”)
大小=pkt.sprintf(“%IP.len%”)
#初始化
如果(src、dst)不在通信量中:
交通量[(src,dst)]=0
其他:
交通量[(src,dst)]+=int(大小)
嗅探(iface=“eth1”,prn=流量\监视器\调用,存储=0,超时=采样\间隔)
#按总字节排序,降序
traffic\u sorted=sorted(traffic.iteritems(),key=itemgetter(1),reverse=True)
#打印前10名谈话者
对于范围(0,10)内的x:
src=已排序的流量[x][0][0]
dst=已排序的流量[x][0][1]
主机总数=已排序的流量[x][3]
#从IP获取主机名
尝试:
src_hostname=socket.gethostbyaddr(src)
除:
src_hostname=src
尝试:
dst_hostname=socket.gethostbyaddr(dst)
除:
dst_主机名=dst
打印“%s:%s(%s)->%s(%s)”%(人(主机总数)、src_主机名[0]、src、dst_主机名[0]、dst)
我不确定这是一个编程(scapy/python)问题还是一个更一般的网络问题,所以我把它称为一个网络编程问题。这可能不是问题,但你是不是把每秒兆字节数(Mb/s)和每秒兆字节数(Mb/s)混在一起了?您似乎正在测量以字节为单位发送的数据量,然后将其转换为MB/s,但我想知道您是否将uo ws spec的位同步设置为1.5 MB/s。如果是这样的话,脚本为您提供200 kB/s的速度至少在1.5 Mb/s的正确范围内。 嗨 首先,您发布的代码中有一个bug:您可能指的是
host\u total=traffic\u sorted[x][3]
,而不是host\u total=traffic\u sorted[x][1]
然后,您出现了一个错误:您忘了将host\u total
除以sample\u interval
值
由于您还希望添加接收方到发送方的通信量和发送方到接收方的通信量,我认为最好的方法是使用“有序”元组(顺序本身在这里并不重要,字典顺序可能很好,但您也可以使用算术顺序,因为IP地址是4个八位整数)作为计数器
对象的键。这似乎很管用:
#! /usr/bin/env python
sample_interval = 10
interface="eth1"
from scapy.all import *
from collections import Counter
# Counter is a *much* better option for what you're doing here. See
# http://docs.python.org/2/library/collections.html#collections.Counter
traffic = Counter()
# You should probably use a cache for your IP resolutions
hosts = {}
def human(num):
for x in ['', 'k', 'M', 'G', 'T']:
if num < 1024.: return "%3.1f %sB" % (num, x)
num /= 1024.
# just in case!
return "%3.1f PB" % (num)
def traffic_monitor_callback(pkt):
if IP in pkt:
pkt = pkt[IP]
# You don't want to use sprintf here, particularly as you're
# converting .len after that!
# Here is the first place where you're happy to use a Counter!
# We use a tuple(sorted()) because a tuple is hashable (so it
# can be used as a key in a Counter) and we want to sort the
# addresses to count mix sender-to-receiver traffic together
# with receiver-to-sender
traffic.update({tuple(sorted(map(atol, (pkt.src, pkt.dst)))): pkt.len})
sniff(iface=interface, prn=traffic_monitor_callback, store=False,
timeout=sample_interval)
# ... and now comes the second place where you're happy to use a
# Counter!
# Plus you can use value unpacking in your for statement.
for (h1, h2), total in traffic.most_common(10):
# Let's factor out some code here
h1, h2 = map(ltoa, (h1, h2))
for host in (h1, h2):
if host not in hosts:
try:
rhost = socket.gethostbyaddr(host)
hosts[host] = rhost[0]
except:
hosts[host] = None
# Get a nice output
h1 = "%s (%s)" % (hosts[h1], h1) if hosts[h1] is not None else h1
h2 = "%s (%s)" % (hosts[h2], h2) if hosts[h2] is not None else h2
print "%s/s: %s - %s" % (human(float(total)/sample_interval), h1, h2)
我正在rsync中使用
--bwlimit=1500
选项manrsync
说这是限制I/O带宽;每秒千字节,因此大约为1.5兆字节/秒。我可以与iftop以及(仙人掌)确认[图表显示,我确实在推送这么多的流量。感谢您的澄清。是的,我相信您关于发送方和接收方流量的看法是正确的。在查看iftop
的输出时,我可以看到它显示了两台主机之间的组合流量。在最后合并结果,即合并元组,这是一种很好的python方式吗?例如e、 如果在(主机1,主机2)+(主机2,主机1)的通信量中有结果。刚刚更新了我的答案。这完全回答了你的问题吗?哇,代码很好。比我的效率和聪明得多:)。我仍然很好奇,为什么每个主机对的最终总数仍然如此之低,即使在交通方向合并的情况下,与iftop
并排比较时?iftop
似乎是正确的我的限制rsync测试。也许采样间隔应该设置得更高,比如说60秒?我想知道iftop
在幕后是怎么做的…这可能是最好的例子,因为我几乎在尝试构建相同的东西,但是使用scapy
。该死!所以这仍然不是你问题的好答案!我已经升级了我的答案是,检查Scapy是否太慢,是否丢失了数据包。是的,这看起来更准确!总数最终略高,但看起来要好得多。有没有办法让Scapy查看最后X秒的时间戳?也就是说,我将Scapy指向一个不断更新的tcpdump cap文件,Scapy只需抓取最后X秒f你不必花时间在上面,除非你想:)。另外,你能编辑你的答案,只显示最后的代码和解释吗
#! /usr/bin/env python
sample_interval = 10
interface="eth1"
from scapy.all import *
from collections import Counter
# Counter is a *much* better option for what you're doing here. See
# http://docs.python.org/2/library/collections.html#collections.Counter
traffic = Counter()
# You should probably use a cache for your IP resolutions
hosts = {}
def human(num):
for x in ['', 'k', 'M', 'G', 'T']:
if num < 1024.: return "%3.1f %sB" % (num, x)
num /= 1024.
# just in case!
return "%3.1f PB" % (num)
def traffic_monitor_callback(pkt):
if IP in pkt:
pkt = pkt[IP]
# You don't want to use sprintf here, particularly as you're
# converting .len after that!
# Here is the first place where you're happy to use a Counter!
# We use a tuple(sorted()) because a tuple is hashable (so it
# can be used as a key in a Counter) and we want to sort the
# addresses to count mix sender-to-receiver traffic together
# with receiver-to-sender
traffic.update({tuple(sorted(map(atol, (pkt.src, pkt.dst)))): pkt.len})
sniff(iface=interface, prn=traffic_monitor_callback, store=False,
timeout=sample_interval)
# ... and now comes the second place where you're happy to use a
# Counter!
# Plus you can use value unpacking in your for statement.
for (h1, h2), total in traffic.most_common(10):
# Let's factor out some code here
h1, h2 = map(ltoa, (h1, h2))
for host in (h1, h2):
if host not in hosts:
try:
rhost = socket.gethostbyaddr(host)
hosts[host] = rhost[0]
except:
hosts[host] = None
# Get a nice output
h1 = "%s (%s)" % (hosts[h1], h1) if hosts[h1] is not None else h1
h2 = "%s (%s)" % (hosts[h2], h2) if hosts[h2] is not None else h2
print "%s/s: %s - %s" % (human(float(total)/sample_interval), h1, h2)
#! /usr/bin/env python
sample_interval = 10
filename="capture.cap"
from scapy.all import *
from collections import Counter
traffic = Counter()
hosts = {}
def human(num):
for x in ['', 'k', 'M', 'G', 'T']:
if num < 1024.: return "%3.1f %sB" % (num, x)
num /= 1024.
return "%3.1f PB" % (num)
def traffic_monitor_callback(pkt):
if IP in pkt:
pkt = pkt[IP]
traffic.update({tuple(sorted(map(atol, (pkt.src, pkt.dst)))): pkt.len})
# A trick I like: don't use rdpcap() that would waste your memory;
# iterate over a PcapReader object instead.
for p in PcapReader("capture.cap"):
traffic_monitor_callback(p)
for (h1, h2), total in traffic.most_common(10):
h1, h2 = map(ltoa, (h1, h2))
for host in (h1, h2):
if host not in hosts:
try:
rhost = socket.gethostbyaddr(host)
hosts[host] = rhost[0]
except:
hosts[host] = None
h1 = "%s (%s)" % (hosts[h1], h1) if hosts[h1] is not None else h1
h2 = "%s (%s)" % (hosts[h2], h2) if hosts[h2] is not None else h2
print "%s/s: %s - %s" % (human(float(total)/sample_interval), h1, h2)