在工作中,测试Phy实际数据速率时,需要对设备实际发出的数据进行报文数据量统计。最初按照以往的项目经验,以及scapy对于报文解析比较友好,使用python的scapy进行脚本的编辑。但是实际使用发现,对于单个大数据包(单个1G附近)的报文分析,耗时较长,总共数据分析完需要数十分钟,无法满足实际验证需求。
在一番搜索后,使用dpkt模块会极大加快处理速度,从而将此次解决进行分享。
耗时较长的原因是scapy的rdpcap在读取报文时,会将整个文件都加载到内存,这个是最耗时的部分,而且当Tester的内存不足时,也会造成异常。(之前在rdpcap读取文件后,自己进行了迭代器的处理,但是依旧耗时的原因)
dpkt则是依次读取每条报文进行分析(迭代器),相比而言,不需要加载大量数据到内存,减少了处理时间。
dpkt使用
官方链接
dpkt — dpkt 1.9.2 documentation
dpkt | fast, simple packet creation / parsing, with definitions for the basic TCP/IP protocols
import dpkt
file_path = '\xxx\xxx\xx.pcap'
def handle_pcap(pcap_obj):
for ts,buffer in pcap_obj:
#ts为报文的时间戳
#buffer为报文实际的数据(Ethernet层以及上层数据)
print(f'the current message timestamp is {ts}')
print(f'the current message length is {len(buffer)}')
def my_test_dpkt(file_path):
with open(file_path,'rb) as file:
pcap = dpkt.pcap.Reader(file)
print_packets(pcap)
if __name__ == '__main__':
my_test_dpkt(file_path)
注意:使dpkt.pcap.Reader(file)时必须保证file句柄没有被关闭(如果将dpkt.pcap.Reader(file)放于with上下文管理器外,就会导致file已经被关闭,从而导致dpkt报错)。上文代码将其放在with结构中可以避免,如果单独进行文件的操作,一定记得关闭文件。
解析ethernet层数据、参数
for ts,item in pcap:
ether_pcaket = dpkt.ethernet.Ethernet(item)
# 解析ethernet层数据
获取IP层数据
import socket
if not hasattr(ether_packet,'ip'): continue #判断报文是否为IP报文
ip_proto = ether_packet.data.p # 获取ip层里面的协议字段
src_ip = socket.inet_ntop(socket.AF_INET,ether_packet.data.src) #获取srcip
#判断报文是否为UDP,其余类似
if ip_proto == dpkt.ip.IP_PROTO_UDP:
#获取UDP payload
udp_layer_data = ether_packet.data.udp.data
#如果想获取指定序号,可以直接按索引获取即可
data1 = udp_layer_data[1:2]
最好的获取各层数据的方法,可以在遍历所有报文(上述代码的循环结构中)时打断点查看每个报文具有的属性,可以获取到对应的数据访问方法,也可参考官方文档的API
实际效果:
使用scapy全部处理时长为数十分钟,使用dpkt处理时间为40s左右,优化效果明显。
使用时遇到问题解决:
如果在dpkt使用中出现 Invalid tcpdump header报错,是因为文件格式不对。pcap和pcapng前四个字节不同,这可以查询dpkt源代码确认。dpkt.pcap.Reader()仅支持pcap格式。
Github链接:
https://github.com/kbandla/dpkt/blob/master/dpkt/pcap.py
如果将pcapng直接修改后缀为pcap,也会报该错误。
如何解决
方法1:
重新抓包,保存时一定注意保存格式为pcap
方法2:
使用wireshark重新打开包,另存为pcap
方法3:
ubuntu下可以使用如下指令进行格式的修改:
editcap -F libpcap -T ether fault_file_type.pcap right_file_type.pcap
# fault_file_type.pcap格式错误的文档
# right_file_type.pcap正确格式的新文件名
方法4:
使用dpkt.pcapng.Reader()进行pcapng文件的读取分析。
Github链接: