import sys
import psutil
import pyshark
from PySide6.QtWidgets import (
    QApplication, QMainWindow, QVBoxLayout, QWidget,
    QTableWidget, QTableWidgetItem, QHeaderView, QComboBox,
    QHBoxLayout, QLabel, QLineEdit, QMessageBox
)
from PySide6.QtCore import Qt, QThread, Signal, QTimer, QSize
from PySide6.QtGui import QIcon, QPixmap
from collections import defaultdict
import win32gui
import win32ui
import win32con
from PIL import Image
import threading
import os
import ctypes

def make_transparent(image):
    image = image.convert("RGBA")
    datas = image.getdata()
    new_data = []
    for item in datas:
        if item[0] == 0 and item[1] == 0 and item[2] == 0:
            new_data.append((255, 255, 255, 0))
        else:
            new_data.append(item)
    image.putdata(new_data)
    return image

class NetworkMonitorThread(QThread):
    update_signal = Signal(list)

    def __init__(self, interface, parent=None):
        super().__init__(parent)
        self.running = True
        self.process_net_io = defaultdict(lambda: {'bytes_recv': 0, 'bytes_sent': 0, 'name': ''})
        self.lock = threading.Lock()
        self.capture = None
        self.interface = interface

    def run(self):
        if not self.interface:
            print("未选择网络接口，无法进行数据包捕获。")
            return

        try:
            self.capture = pyshark.LiveCapture(interface=self.interface, bpf_filter='tcp or udp')
            print(f"开始在接口 {self.interface} 上捕获数据包...")

            for packet in self.capture.sniff_continuously():
                if not self.running:
                    self.capture.close()
                    break
                try:
                    if 'IP' not in packet:
                        continue
                    src_ip = packet.ip.src
                    dst_ip = packet.ip.dst
                    protocol = packet.transport_layer
                    src_port = packet[packet.transport_layer].srcport
                    dst_port = packet[packet.transport_layer].dstport
                    packet_length = int(packet.length)

                    # 查找与源 IP:port 相关的进程
                    src_pid = self.get_pid(src_ip, src_port, protocol)
                    if src_pid:
                        with self.lock:
                            self.process_net_io[src_pid]['bytes_sent'] += packet_length

                    # 查找与目标 IP:port 相关的进程
                    dst_pid = self.get_pid(dst_ip, dst_port, protocol)
                    if dst_pid:
                        with self.lock:
                            self.process_net_io[dst_pid]['bytes_recv'] += packet_length

                except Exception as e:
                    print(f"处理数据包时出错: {e}")

        except Exception as e:
            print(f"初始化数据包捕获时出错: {e}")
            return

        # 捕获结束后更新 UI
        self.update_ui()

    def get_pid(self, ip, port, protocol):
        try:
            for proc in psutil.process_iter(['pid', 'name', 'connections']):
                for conn in proc.info['connections']:
                    if conn.laddr and conn.laddr.ip == ip and conn.laddr.port == int(port):
                        return proc.info['pid']
            return None
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            return None

    def update_ui(self):
        with self.lock:
            data = []
            for pid, io in self.process_net_io.items():
                if io['bytes_recv'] > 0 or io['bytes_sent'] > 0:
                    try:
                        proc = psutil.Process(pid)
                        name = proc.name()
                        data.append((
                            name,
                            io['bytes_recv'] / 1024,  # KB
                            io['bytes_sent'] / 1024,  # KB
                            io['bytes_recv'] / (1024 * 1024),  # MB
                            io['bytes_sent'] / (1024 * 1024)   # MB
                        ))
                    except (psutil.NoSuchProcess, psutil.AccessDenied):
                        continue
            # 重置统计
            self.process_net_io = defaultdict(lambda: {'bytes_recv': 0, 'bytes_sent': 0, 'name': ''})
            self.update_signal.emit(data)

    def stop(self):
        self.running = False
        if self.capture:
            self.capture.close()

class NetworkMonitor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("网络流量监控")
        self.setGeometry(100, 100, 900, 600)

        self.table = QTableWidget(self)
        self.table.setColumnCount(6)
        self.table.setHorizontalHeaderLabels(["图标", "进程", "下载速度 (KB/s)", "上传速度 (KB/s)", "下载量 (MB)", "上传量 (MB)"])
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.table.setIconSize(QSize(32, 32))

        layout = QVBoxLayout()
        layout.addWidget(self.table)

        # 接口选择部分
        interface_label = QLabel("选择网络接口:")
        self.interface_combo = QComboBox()
        self.interface_combo.currentIndexChanged.connect(self.change_interface)

        # 排序方式选择
        self.sort_combo = QComboBox()
        self.sort_combo.addItem("按下载速度排序")
        self.sort_combo.addItem("按进程名称排序")
        self.sort_combo.currentIndexChanged.connect(self.update_network_info)

        # 过滤输入框
        self.filter_input = QLineEdit(self)
        self.filter_input.setPlaceholderText("按进程名称过滤")
        self.filter_input.textChanged.connect(self.update_network_info)

        # 布局设置
        control_layout = QHBoxLayout()
        control_layout.addWidget(interface_label)
        control_layout.addWidget(self.interface_combo)
        control_layout.addSpacing(20)
        control_layout.addWidget(QLabel("排序方式:"))
        control_layout.addWidget(self.sort_combo)
        control_layout.addSpacing(20)
        control_layout.addWidget(QLabel("过滤:"))
        control_layout.addWidget(self.filter_input)
        layout.addLayout(control_layout)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.icon_cache = {}
        self.default_icon = QIcon("default_icon.png")  # 确保此路径有默认图标

        # 定时器，用于定期刷新表格
        self.ui_timer = QTimer()
        self.ui_timer.timeout.connect(self.refresh_table)
        self.ui_timer.start(2000)  # 每2秒刷新一次

        # 存储最新的数据
        self.latest_data = []

        # 初始化接口列表
        self.init_interfaces()

    def init_interfaces(self):
        try:
            interfaces = pyshark.LiveCapture.interfaces()
            print("可用的网络接口:")
            for idx, iface in enumerate(interfaces):
                print(f"{idx}: {iface}")
        except Exception as e:
            print(f"获取接口时出错: {e}")
            interfaces = []

        # 过滤掉不需要的接口
        valid_interfaces = []
        for iface in interfaces:
            if "Loopback" not in iface and "etwdump" not in iface and "vEthernet" not in iface:
                valid_interfaces.append(iface)

        if not valid_interfaces:
            QMessageBox.critical(self, "错误", "未找到合适的网络接口进行捕获。")
            return

        # 添加接口到下拉框
        self.interface_combo.addItems(valid_interfaces)

        # 默认选择第一个接口并启动监控
        self.interface_combo.setCurrentIndex(0)
        self.start_monitoring(valid_interfaces[0])

    def change_interface(self, index):
        selected_interface = self.interface_combo.currentText()
        if selected_interface:
            self.start_monitoring(selected_interface)

    def start_monitoring(self, interface):
        # 停止已有的监控线程
        if hasattr(self, 'network_thread') and self.network_thread.isRunning():
            self.network_thread.stop()
            self.network_thread.wait()

        # 启动新的监控线程
        print(f"选择的接口: {interface}")
        self.network_thread = NetworkMonitorThread(interface, self)
        self.network_thread.update_signal.connect(self.update_table)
        self.network_thread.start()

    def update_table(self, sorted_data):
        self.latest_data = sorted_data

    def refresh_table(self):
        if not self.latest_data:
            return

        filter_text = self.filter_input.text().lower()
        filtered_data = [data for data in self.latest_data if filter_text in data[0].lower() or not filter_text]

        sort_by = self.sort_combo.currentIndex()
        if sort_by == 0:
            # 按下载速度排序
            filtered_data.sort(key=lambda x: x[1], reverse=True)
        else:
            # 按进程名称排序
            filtered_data.sort(key=lambda x: x[0])

        self.table.setRowCount(len(filtered_data))
        for row, data in enumerate(filtered_data):
            process_name = data[0]
            icon_item = QTableWidgetItem()
            icon = self.get_exe_icon(process_name)
            if icon:
                icon_item.setIcon(icon)
            else:
                icon_item.setIcon(self.default_icon)  # 使用默认图标
            self.table.setItem(row, 0, icon_item)

            # 设置进程名称
            self.table.setItem(row, 1, QTableWidgetItem(process_name))

            # 设置下载速度
            self.table.setItem(row, 2, QTableWidgetItem(f"{data[1]:.2f}"))

            # 设置上传速度
            self.table.setItem(row, 3, QTableWidgetItem(f"{data[2]:.2f}"))

            # 设置下载量
            self.table.setItem(row, 4, QTableWidgetItem(f"{data[3]:.2f}"))

            # 设置上传量
            self.table.setItem(row, 5, QTableWidgetItem(f"{data[4]:.2f}"))

    def get_exe_icon(self, process_name):
        if process_name in self.icon_cache:
            return self.icon_cache[process_name]

        try:
            exe_path = None
            for proc in psutil.process_iter(['pid', 'name', 'exe']):
                if proc.info['name'] == process_name:
                    exe_path = proc.info['exe']
                    break

            if not exe_path or not os.path.exists(exe_path):
                return None

            large, _ = win32gui.ExtractIconEx(exe_path, 0)
            if not large:
                return None

            hdc = win32gui.GetDC(0)
            hdc = win32ui.CreateDCFromHandle(hdc)
            hbmp = win32ui.CreateBitmap()
            hbmp.CreateCompatibleBitmap(hdc, 32, 32)

            hdc_mem = hdc.CreateCompatibleDC()
            hdc_mem.SelectObject(hbmp)
            win32gui.DrawIconEx(hdc_mem.GetSafeHdc(), 0, 0, large[0], 32, 32, 0, None, win32con.LR_ICON)

            bmpinfo = hbmp.GetInfo()
            bmpstr = hbmp.GetBitmapBits(True)
            img = Image.frombuffer(
                'RGB',
                (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
                bmpstr, 'raw', 'BGRX', 0, 1
            )

            img = make_transparent(img)
            img_path = f'temp_icon_{process_name}.png'
            img.save(img_path)
            pixmap = QPixmap(img_path)

            icon = QIcon(pixmap)
            self.icon_cache[process_name] = icon

            # 清理临时图标文件
            if os.path.exists(img_path):
                os.remove(img_path)

            return icon
        except Exception as e:
            print(f"提取图标时出错: {e}")
            return None

    def update_network_info(self):
        pass  # 排序和过滤逻辑已经在 refresh_table 中处理

    def closeEvent(self, event):
        if hasattr(self, 'network_thread') and self.network_thread.isRunning():
            self.network_thread.stop()
            self.network_thread.wait()
        super().closeEvent(event)

if __name__ == "__main__":
    # 检查是否以管理员身份运行
    try:
        is_admin = ctypes.windll.shell32.IsUserAnAdmin()
    except:
        is_admin = False

    if not is_admin:
        print("请以管理员身份运行此程序以获取完整的网络监控功能。")
        ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
        sys.exit()

    app = QApplication(sys.argv)
    window = NetworkMonitor()
    window.show()
    sys.exit(app.exec())
我已经以管理员身份运行脚本了，但是运行后提示未找到合适的网络接口进行捕获，怎么办，中文回复我