Administrator
发布于 2025-02-01 / 11 阅读 / 0 评论 / 0 点赞

mac 网络控制器

import tkinter as tk
from tkinter import ttk, messagebox
import json
import os
import platform
import netifaces
import subprocess
import ipaddress


class NetworkManager:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("网卡配置管理器")
        self.root.geometry("600x600")

        self.os_type = platform.system()
        self.config_file = "network_config.json"
        self.load_saved_configs()

        self.setup_ui()

    def log_message(self, message):
        """添加日志消息到日志区域"""
        self.log_text.insert(tk.END, f"{message}\n")
        self.log_text.see(tk.END)  # 自动滚动到最新消息

    def load_saved_configs(self):
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r') as f:
                    self.saved_configs = json.load(f)
            else:
                self.saved_configs = {}
        except Exception as e:
            messagebox.showerror("错误", f"加载配置文件失败: {str(e)}")
            self.saved_configs = {}

    def save_config(self):
        config = {
            'ip': self.ip_entry.get(),
            'subnet': self.subnet_entry.get(),
            'gateway': self.gateway_entry.get(),
            'dns': self.dns_entry.get()
        }

        config_name = self.config_name_entry.get()
        if not config_name:
            messagebox.showerror("错误", "请输入配置名称")
            return

        self.saved_configs[config_name] = config
        try:
            with open(self.config_file, 'w') as f:
                json.dump(self.saved_configs, f, indent=4)
            self.update_config_dropdown()
            messagebox.showinfo("成功", "配置已保存")
        except Exception as e:
            messagebox.showerror("错误", f"保存配置失败: {str(e)}")

    def get_network_interfaces(self):
        interfaces = []
        try:
            for iface in netifaces.interfaces():
                # 排除回环接口
                if iface != 'lo' and iface != 'lo0':
                    interfaces.append(iface)
            return interfaces
        except Exception as e:
            messagebox.showerror("错误", f"获取网卡信息失败: {str(e)}")
            return []

    def setup_ui(self):
        # 网卡选择
        ttk.Label(self.root, text="选择网卡:").grid(row=0, column=0, padx=5, pady=5)
        self.interface_var = tk.StringVar()
        self.interface_combo = ttk.Combobox(self.root, textvariable=self.interface_var)

        # 获取网络服务列表
        services_output = subprocess.check_output(['networksetup', '-listallnetworkservices']).decode()
        services = [s.strip() for s in services_output.split('\n')
                    if s.strip() and not s.startswith('An asterisk')]
        self.interface_combo['values'] = services
        self.interface_combo.grid(row=0, column=1, columnspan=2, padx=5, pady=5, sticky="ew")

        # 日志显示区域
        log_frame = ttk.LabelFrame(self.root, text="操作日志")
        log_frame.grid(row=5, column=0, columnspan=3, padx=5, pady=5, sticky="nsew")

        self.log_text = tk.Text(log_frame, height=8, width=50)
        self.log_text.pack(padx=5, pady=5, fill=tk.BOTH, expand=True)

        # 添加滚动条
        scrollbar = ttk.Scrollbar(log_frame, command=self.log_text.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.log_text.configure(yscrollcommand=scrollbar.set)

        # 配置root窗口的行列权重
        self.root.grid_rowconfigure(5, weight=1)
        self.root.grid_columnconfigure(0, weight=1)

        # IP模式选择
        self.ip_mode = tk.StringVar(value="dhcp")
        ttk.Radiobutton(self.root, text="DHCP", variable=self.ip_mode,
                        value="dhcp", command=self.toggle_ip_mode).grid(row=1, column=0, padx=5, pady=5)
        ttk.Radiobutton(self.root, text="静态IP", variable=self.ip_mode,
                        value="static", command=self.toggle_ip_mode).grid(row=1, column=1, padx=5, pady=5)

        # IP配置区域
        self.config_frame = ttk.LabelFrame(self.root, text="IP配置")
        self.config_frame.grid(row=2, column=0, columnspan=3, padx=5, pady=5, sticky="nsew")

        ttk.Label(self.config_frame, text="IP地址:").grid(row=0, column=0, padx=5, pady=5)
        self.ip_entry = ttk.Entry(self.config_frame)
        self.ip_entry.grid(row=0, column=1, padx=5, pady=5)

        ttk.Label(self.config_frame, text="子网掩码:").grid(row=1, column=0, padx=5, pady=5)
        self.subnet_entry = ttk.Entry(self.config_frame)
        self.subnet_entry.grid(row=1, column=1, padx=5, pady=5)

        ttk.Label(self.config_frame, text="网关:").grid(row=2, column=0, padx=5, pady=5)
        self.gateway_entry = ttk.Entry(self.config_frame)
        self.gateway_entry.grid(row=2, column=1, padx=5, pady=5)

        ttk.Label(self.config_frame, text="DNS:").grid(row=3, column=0, padx=5, pady=5)
        self.dns_entry = ttk.Entry(self.config_frame)
        self.dns_entry.grid(row=3, column=1, padx=5, pady=5)

        # 保存配置区域
        save_frame = ttk.LabelFrame(self.root, text="保存配置")
        save_frame.grid(row=3, column=0, columnspan=3, padx=5, pady=5, sticky="nsew")

        ttk.Label(save_frame, text="配置名称:").grid(row=0, column=0, padx=5, pady=5)
        self.config_name_entry = ttk.Entry(save_frame)
        self.config_name_entry.grid(row=0, column=1, padx=5, pady=5)

        ttk.Button(save_frame, text="保存配置", command=self.save_config).grid(row=0, column=2, padx=5, pady=5)

        # 加载配置下拉框
        ttk.Label(save_frame, text="加载配置:").grid(row=1, column=0, padx=5, pady=5)
        self.config_var = tk.StringVar()
        self.config_dropdown = ttk.Combobox(save_frame, textvariable=self.config_var)
        self.config_dropdown.grid(row=1, column=1, padx=5, pady=5)
        self.config_dropdown.bind('<<ComboboxSelected>>', self.load_selected_config)
        self.update_config_dropdown()

        # 应用按钮
        ttk.Button(self.root, text="应用配置", command=self.apply_network_config).grid(row=4, column=0, columnspan=3,
                                                                                       pady=10)

        self.toggle_ip_mode()

    def update_config_dropdown(self):
        self.config_dropdown['values'] = list(self.saved_configs.keys())

    def load_selected_config(self, event=None):
        selected = self.config_var.get()
        if selected in self.saved_configs:
            config = self.saved_configs[selected]
            # 先设置为静态IP模式
            self.ip_mode.set("static")
            self.toggle_ip_mode()

            # 然后填充配置
            self.ip_entry.delete(0, tk.END)
            self.ip_entry.insert(0, config['ip'])
            self.subnet_entry.delete(0, tk.END)
            self.subnet_entry.insert(0, config['subnet'])
            self.gateway_entry.delete(0, tk.END)
            self.gateway_entry.insert(0, config['gateway'])
            self.dns_entry.delete(0, tk.END)
            self.dns_entry.insert(0, config['dns'])

            self.log_message(f"已加载配置 '{selected}'")
            self.log_message(f"IP: {config['ip']}")
            self.log_message(f"子网掩码: {config['subnet']}")
            self.log_message(f"网关: {config['gateway']}")
            self.log_message(f"DNS: {config['dns']}")

    def toggle_ip_mode(self):
        state = "disabled" if self.ip_mode.get() == "dhcp" else "normal"
        self.ip_entry.configure(state=state)
        self.subnet_entry.configure(state=state)
        self.gateway_entry.configure(state=state)
        self.dns_entry.configure(state=state)

    def validate_ip_config(self):
        if self.ip_mode.get() == "static":
            try:
                ipaddress.ip_address(self.ip_entry.get())
                ipaddress.ip_address(self.subnet_entry.get())
                ipaddress.ip_address(self.gateway_entry.get())
                ipaddress.ip_address(self.dns_entry.get())
                return True
            except ValueError as e:
                messagebox.showerror("错误", f"IP配置无效: {str(e)}")
                return False
        return True

    def apply_network_config(self):
        if not self.validate_ip_config():
            return

        interface = self.interface_var.get()
        if not interface:
            messagebox.showerror("错误", "请选择网卡")
            return

        try:
            if self.os_type == "Windows":
                self.apply_windows_config(interface)
            elif self.os_type == "Darwin":  # macOS
                self.apply_macos_config(interface)
            else:
                messagebox.showerror("错误", "不支持的操作系统")
        except Exception as e:
            messagebox.showerror("错误", f"应用配置失败: {str(e)}")

    def apply_windows_config(self, interface):
        if self.ip_mode.get() == "dhcp":
            cmd = f'netsh interface ip set address "{interface}" dhcp'
            subprocess.run(cmd, shell=True, check=True)
            cmd = f'netsh interface ip set dns "{interface}" dhcp'
            subprocess.run(cmd, shell=True, check=True)
        else:
            cmd = f'netsh interface ip set address "{interface}" static {self.ip_entry.get()} {self.subnet_entry.get()} {self.gateway_entry.get()}'
            subprocess.run(cmd, shell=True, check=True)
            cmd = f'netsh interface ip set dns "{interface}" static {self.dns_entry.get()}'
            subprocess.run(cmd, shell=True, check=True)

        messagebox.showinfo("成功", "网络配置已更新")

    def verify_macos_service(self, service_name):
        """验证网络服务是否存在且可用"""
        try:
            subprocess.check_output(['networksetup', '-getinfo', service_name])
            return True
        except subprocess.CalledProcessError:
            return False

    def apply_macos_config(self, interface):
        try:
            self.log_message("\n开始配置网络...")
            service_name = interface  # 直接使用选择的网络服务名称
            self.log_message(f"使用网络服务: {service_name}")

            if self.ip_mode.get() == "dhcp":
                self.log_message("配置DHCP模式...")
                cmd = ['networksetup', '-setdhcp', service_name]
                self.log_message(f"执行命令: {' '.join(cmd)}")

                result = subprocess.run(cmd, capture_output=True, text=True)
                if result.returncode != 0:
                    error_msg = f"设置DHCP失败: {result.stderr}"
                    self.log_message(error_msg)
                    raise Exception(error_msg)

                self.log_message("DHCP配置成功")
                messagebox.showinfo("成功", "已切换至DHCP模式")
            else:
                self.log_message("配置静态IP模式...")
                # 设置IP地址和子网掩码
                cmd = [
                    'networksetup',
                    '-setmanual',
                    service_name,
                    self.ip_entry.get(),
                    self.subnet_entry.get(),
                    self.gateway_entry.get()
                ]
                self.log_message(f"执行命令: {' '.join(cmd)}")

                result = subprocess.run(cmd, capture_output=True, text=True)
                if result.returncode != 0:
                    error_msg = f"设置IP失败: {result.stderr}"
                    self.log_message(error_msg)
                    raise Exception(error_msg)

                self.log_message("静态IP配置成功")

                # 设置DNS服务器
                if self.dns_entry.get().strip():
                    dns_cmd = [
                        'networksetup',
                        '-setdnsservers',
                        service_name,
                        self.dns_entry.get()
                    ]
                    self.log_message(f"设置DNS,执行命令: {' '.join(dns_cmd)}")

                    dns_result = subprocess.run(dns_cmd, capture_output=True, text=True)
                    if dns_result.returncode != 0:
                        error_msg = f"设置DNS失败: {dns_result.stderr}"
                        self.log_message(error_msg)
                        raise Exception(error_msg)

                    self.log_message("DNS配置成功")

            self.log_message("网络配置已全部更新完成")
            messagebox.showinfo("成功", "网络配置已更新")

        except subprocess.CalledProcessError as e:
            error_msg = f"网络配置命令执行失败: {e.stderr if hasattr(e, 'stderr') else str(e)}"
            print(error_msg)
            raise Exception(error_msg)
        except Exception as e:
            error_msg = f"配置网络时出错: {str(e)}"
            print(error_msg)
            raise Exception(error_msg)

            # 获取网络服务名称
            services_output = subprocess.check_output(['networksetup', '-listallnetworkservices']).decode()
            services = services_output.split('\n')
            service_name = None

            # 查找对应接口的网络服务名称
            for service in services:
                if service.strip() and not service.startswith('An asterisk'):
                    try:
                        # 获取该服务对应的硬件端口
                        hardware_port = subprocess.check_output(
                            ['networksetup', '-getadapter', service]
                        ).decode().strip().split(': ')[-1]

                        print(f"检查服务: {service}, 硬件端口: {hardware_port}")  # 调试信息

                        if hardware_port.lower() == interface.lower():
                            service_name = service
                            print(f"找到匹配服务: {service}")  # 调试信息
                            break
                    except subprocess.CalledProcessError:
                        continue

            if not service_name:
                raise Exception(f"找不到网卡 {interface} 对应的网络服务")

            if self.ip_mode.get() == "dhcp":
                # 设置DHCP
                subprocess.run(['networksetup', '-setdhcp', service_name], check=True)
            else:
                # 设置静态IP
                subprocess.run([
                    'networksetup',
                    '-setmanualwithdhcprouter',  # 使用当前DHCP路由器
                    service_name,
                    self.ip_entry.get(),
                    self.subnet_entry.get()
                ], check=True)

                # 设置DNS
                dns_servers = self.dns_entry.get().split()  # 支持多个DNS服务器
                subprocess.run(['networksetup', '-setdnsservers', service_name] + dns_servers, check=True)

                # 设置网关
                if self.gateway_entry.get():
                    subprocess.run(['route', '-n', 'add', '-net', 'default', self.gateway_entry.get()], check=True)

            messagebox.showinfo("成功", "网络配置已更新")

        except subprocess.CalledProcessError as e:
            raise Exception(f"网络配置命令执行失败: {str(e)}")
        except Exception as e:
            raise Exception(f"配置网络时出错: {str(e)}")

    def run(self):
        self.root.mainloop()


if __name__ == "__main__":
    app = NetworkManager()
    app.run()

评论