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()