如何使用Scapy按固定时间间隔捕获UDP数据包并保存为pcap文件
问题根因
你原有代码的核心问题是完全没有执行真实网卡抓包逻辑,只是手动构造了一个仅包含以太网帧头、IP头、UDP头的空数据包,三层协议头总长度恰好为42字节,没有携带任何UDP载荷,这才是生成的pcap文件和Wireshark捕获结果长度、内容不一致的根本原因,和采集预留时长没有关系。
实现思路
要完成真实UDP流量捕获、按固定时间间隔滚动保存pcap文件的需求,直接基于scapy的sniff抓包接口配合定时缓存逻辑即可:
- 绑定连接传感器的物理网卡,配置BPF过滤规则仅捕获目标传感器发来的UDP流量,过滤无关数据包
- 维护临时数据包缓存列表,启动后台守护线程按设定间隔(比如5秒)将缓存内的数据包写入带时间戳命名的pcap文件,写入完成后清空缓存进入下一个计数周期
- 抓包过程直接保留网卡收到的完整原始帧,不需要手动构造各层协议头
可直接运行的代码
import time import threading from scapy.all import sniff, wrpcap, get_if_list # -------------------------- 参数配置 -------------------------- # 抓包网卡,不确定可先运行print(get_if_list())查看所有可用网卡名 CAPTURE_IFACE = "以太网" # BPF抓包过滤规则,替换为传感器实际IP,只抓对应UDP流量,不需要过滤可留空字符串 CAPTURE_FILTER = "udp and src host 替换为传感器IP地址" # pcap文件保存间隔,单位秒 SAVE_INTERVAL = 5 # ---------------------------------------------------------------- packet_buffer = [] def save_job(): """定时保存缓存数据包的后台任务""" while True: time.sleep(SAVE_INTERVAL) if not packet_buffer: continue # 用时间戳命名文件避免覆盖 file_name = f"sensor_capture_{int(time.time())}.pcap" wrpcap(file_name, packet_buffer) # 清空缓存准备下一轮采集 packet_buffer.clear() def packet_handler(pkt): """抓包回调,将抓到的原始包加入缓存""" packet_buffer.append(pkt) if __name__ == "__main__": # 启动定时保存后台线程 threading.Thread(target=save_job, daemon=True).start() print(f"抓包已启动,每{SAVE_INTERVAL}秒自动保存一个pcap文件,按Ctrl+C终止程序") # store=0 关闭scapy自带的全局缓存,避免长时间运行占用过多内存 sniff(iface=CAPTURE_IFACE, filter=CAPTURE_FILTER, prn=packet_handler, store=0)
运行注意事项
- 抓包需要管理员权限:Windows下右键以管理员身份运行终端/IDE,Linux/macOS下加sudo执行脚本
- 网卡名必须匹配实际接传感器的网卡:Windows可运行
print(get_if_list())打印所有网卡名,Linux可通过ip addr命令查看网卡标识 - 初始调试时可先把
CAPTURE_FILTER设为空字符串,确认能正常抓到传感器流量后再补全过滤规则,避免规则写错漏抓数据 - 生成的pcap文件和脚本在同一目录下,可直接用Wireshark打开校验内容和长度
内容的提问来源于stack exchange,提问作者Ashton Stark
相关产品推荐
相关产品推荐

