diff --git a/app.log b/app.log index 549e7d3..193fca3 100644 --- a/app.log +++ b/app.log @@ -302,3 +302,23 @@ 2025-10-31 17:26:41,880 [INFO] 开始测试202.89.233.100 的 [21, 22, 23, 25, 80, 110, 143, 443, 1433, 3306, 3389] 端口连接情况 2025-10-31 17:26:43,350 [INFO] 开始测试202.89.233.100 的 100 到 1000 端口连接情况 2025-10-31 17:26:44,697 [INFO] 开始测试202.89.233.100 的 [21, 22, 23, 25, 80, 110, 143, 443, 1433, 3306, 3389] 端口连接情况 +2025-10-31 17:31:04,578 [INFO] 开始由 Ping www.feixiangdayezhu.top +2025-10-31 17:31:08,822 [INFO] 停止由 Ping www.feixiangdayezhu.top +2025-10-31 17:31:14,152 [INFO] 测试43.251.226.76 的 443 端口连接情况 +2025-10-31 17:31:39,432 [INFO] 开始测试43.251.226.76 的 [21, 22, 23, 25, 80, 110, 143, 443, 1433, 3306, 3389] 端口连接情况 +2025-10-31 17:31:54,044 [INFO] 开始测试43.251.226.76 的 5000 到 6000 端口连接情况 +2025-10-31 17:33:19,351 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 17:33:23,076 [INFO] 测试202.89.233.100 的 443 端口连接情况 +2025-10-31 17:33:25,235 [INFO] 开始测试202.89.233.100 的 [21, 22, 23, 25, 80, 110, 143, 443, 1433, 3306, 3389] 端口连接情况 +2025-10-31 17:33:28,400 [INFO] 开始测试202.89.233.100 的 100 到 1000 端口连接情况 +2025-10-31 17:54:18,741 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 17:55:53,064 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 17:57:20,180 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 17:58:58,242 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 17:59:44,536 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 18:01:39,713 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 18:10:28,190 [INFO] 测试202.89.233.100 的 443 端口连接情况 +2025-10-31 18:17:02,500 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 18:20:28,569 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 18:21:50,145 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 18:33:44,665 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log diff --git a/core/Function/__pycache__/network_fun.cpython-313.pyc b/core/Function/__pycache__/network_fun.cpython-313.pyc new file mode 100644 index 0000000..86dd543 Binary files /dev/null and b/core/Function/__pycache__/network_fun.cpython-313.pyc differ diff --git a/core/Function/network_fun.py b/core/Function/network_fun.py new file mode 100644 index 0000000..01024c9 --- /dev/null +++ b/core/Function/network_fun.py @@ -0,0 +1,87 @@ +import subprocess +import re + +class NetworkManager: + """获取并设置本机网络适配器信息(Windows)""" + + def get_all_adapters(self): + """返回本机所有网卡信息列表,每个网卡是字典""" + result = subprocess.run("ipconfig /all", capture_output=True, text=True, shell=True) + lines = result.stdout.splitlines() + + adapters = [] + adapter = None + + for line in lines: + line = line.strip() + if not line: + continue + + # 匹配网卡名称 + m = re.match(r'(?:以太网适配器|无线局域网适配器|未知适配器|Ethernet|Wi-Fi|Adapter)\s*(.+):', line) + if m: + if adapter: + adapters.append(adapter) + adapter = { + 'name': m.group(1), + 'ip': '', + 'mask': '', + 'gateway': '', + 'dns1': '', + 'dns2': '', + 'dhcp': '', + 'media': '', + 'desc': '' + } + continue + + if adapter is None: + continue + + # 解析字段 + if "IPv4 地址" in line or "IPv4 Address" in line: + adapter['ip'] = line.split(':')[-1].strip().split('(')[0] + elif "子网掩码" in line or "Subnet Mask" in line: + adapter['mask'] = line.split(':')[-1].strip() + elif "默认网关" in line or "Default Gateway" in line: + if not adapter['gateway']: + adapter['gateway'] = line.split(':')[-1].strip() + elif "DHCP 已启用" in line or "DHCP Enabled" in line: + adapter['dhcp'] = line.split(':')[-1].strip() + elif "媒体状态" in line or "Media State" in line: + adapter['media'] = line.split(':')[-1].strip() + elif "描述" in line or "Description" in line: + adapter['desc'] = line.split(':')[-1].strip() + elif "DNS 服务器" in line or "DNS Servers" in line: + dns = line.split(':')[-1].strip() + if not adapter['dns1']: + adapter['dns1'] = dns + elif not adapter['dns2']: + adapter['dns2'] = dns + + if adapter: + adapters.append(adapter) + + return adapters + + def set_static_ip(self, name, ip, mask, gateway): + """设置静态 IP""" + cmd = f'netsh interface ip set address name="{name}" static {ip} {mask} {gateway} 1' + return subprocess.run(cmd, shell=True, capture_output=True, text=True, encoding="gbk").stdout + + def set_dhcp(self, name): + """切换 DHCP""" + cmd1 = f'netsh interface ip set address name="{name}" dhcp' + cmd2 = f'netsh interface ip set dns name="{name}" dhcp' + out1 = subprocess.run(cmd1, shell=True, capture_output=True, text=True, encoding="gbk").stdout + out2 = subprocess.run(cmd2, shell=True, capture_output=True, text=True, encoding="gbk").stdout + return out1 + "\n" + out2 + + def set_dns(self, name, dns1, dns2=None): + """设置 DNS""" + cmd1 = f'netsh interface ip set dns name="{name}" static {dns1} primary' + out = subprocess.run(cmd1, shell=True, capture_output=True, text=True, encoding="gbk").stdout + if dns2: + cmd2 = f'netsh interface ip add dns name="{name}" {dns2} index=2' + out += subprocess.run(cmd2, shell=True, capture_output=True, text=True, encoding="gbk").stdout + return out diff --git a/core/ui/__pycache__/tab_network.cpython-313.pyc b/core/ui/__pycache__/tab_network.cpython-313.pyc new file mode 100644 index 0000000..704a268 Binary files /dev/null and b/core/ui/__pycache__/tab_network.cpython-313.pyc differ diff --git a/core/ui/__pycache__/tab_telnet.cpython-313.pyc b/core/ui/__pycache__/tab_telnet.cpython-313.pyc index f68e3cc..7eee1ad 100644 Binary files a/core/ui/__pycache__/tab_telnet.cpython-313.pyc and b/core/ui/__pycache__/tab_telnet.cpython-313.pyc differ diff --git a/core/ui/__pycache__/ui_main.cpython-313.pyc b/core/ui/__pycache__/ui_main.cpython-313.pyc index 2f1b5a3..265f4b3 100644 Binary files a/core/ui/__pycache__/ui_main.cpython-313.pyc and b/core/ui/__pycache__/ui_main.cpython-313.pyc differ diff --git a/core/ui/tab_network.py b/core/ui/tab_network.py new file mode 100644 index 0000000..99a2585 --- /dev/null +++ b/core/ui/tab_network.py @@ -0,0 +1,230 @@ +import tkinter as tk +from tkinter import ttk, messagebox, scrolledtext +import threading +import logging + +from core.ui.basic_ui import BasicUI +from core.Function.network_fun import NetworkManager + +logger = logging.getLogger(__name__) + +class NetworkTab(ttk.Frame, BasicUI): + """网卡配置 Tab(兼容最新 NetworkManager)""" + + def __init__(self, parent): + super().__init__(parent) + self.netmgr = NetworkManager() + self._build_ui() + threading.Thread(target=self.refresh_interfaces, daemon=True).start() + + # ---------------- UI 构建 ---------------- + def _build_ui(self): + self.create_iface_section() + self.create_config_section() + self.create_action_section() + self.create_output_section() + self._set_button_state(enabled=True) + + def create_iface_section(self): + frame = ttk.LabelFrame(self, text="网卡选择", padding=8) + frame.pack(side='top', fill='x', padx=10, pady=6) + + self.iface_var = tk.StringVar() + ttk.Label(frame, text="选择网卡:").grid(row=0, column=0, sticky='w') + self.iface_cb = ttk.Combobox(frame, textvariable=self.iface_var, state='readonly', width=40) + self.iface_cb.grid(row=0, column=1, padx=6, pady=2) + self.iface_cb.bind("<>", self.on_iface_selected) + + self.refresh_btn = ttk.Button(frame, text="刷新", width=10, command=self.on_refresh_clicked) + self.refresh_btn.grid(row=0, column=2, padx=6) + + def create_config_section(self): + frame = ttk.LabelFrame(self, text="IP 配置(编辑后点击应用)", padding=8) + frame.pack(side='top', fill='x', padx=10, pady=6) + + self.ip_entry = self.add_input(frame, "IPv4 地址", row=0, col=0, inivar="", entry_width=25) + self.mask_entry = self.add_input(frame, "子网掩码", row=0, col=1, inivar="", entry_width=20) + self.gw_entry = self.add_input(frame, "默认网关", row=1, col=0, inivar="", entry_width=25) + self.dns1_entry = self.add_input(frame, "主 DNS", row=1, col=1, inivar="", entry_width=25) + self.dns2_entry = self.add_input(frame, "备选 DNS", row=1, col=2, inivar="", entry_width=25) + + self.dhcp_var = tk.BooleanVar(value=False) + self.dhcp_chk = ttk.Checkbutton(frame, text="使用 DHCP(自动获取 IP)", variable=self.dhcp_var, + command=self.on_dhcp_toggled) + self.dhcp_chk.grid(row=2, column=0, columnspan=2, sticky='w', pady=6) + + def create_action_section(self): + frame = ttk.Frame(self) + frame.pack(side='top', fill='x', padx=10, pady=6) + self.apply_btn = self.add_button(frame, "应用修改", row=0, col=0, command=self.on_apply_clicked) + self.dhcp_btn = self.add_button(frame, "切换为 DHCP", row=0, col=1, command=self.on_set_dhcp) + self.refresh_info_btn = self.add_button(frame, "刷新当前信息", row=0, col=2, command=self.on_refresh_info) + + def create_output_section(self): + frame = ttk.LabelFrame(self, text="操作日志", padding=6) + frame.pack(side='top', fill='both', expand=True, padx=10, pady=6) + self.result_box = scrolledtext.ScrolledText(frame, width=100, height=12) + self.result_box.pack(fill='both', expand=True, padx=4, pady=4) + + def _set_button_state(self, enabled: bool): + state = 'normal' if enabled else 'disabled' + for btn in [self.apply_btn, self.dhcp_btn, self.refresh_info_btn, self.refresh_btn]: + try: + btn.config(state=state) + except Exception: + pass + + # ---------------- 事件回调 ---------------- + def on_refresh_clicked(self): + self._append_log("刷新网卡列表中...\n") + threading.Thread(target=self.refresh_interfaces, daemon=True).start() + + def refresh_interfaces(self): + try: + adapters = self.netmgr.get_all_adapters() + except Exception as e: + self._append_log(f"获取网卡失败: {e}\n") + return + + names = [a.get("name") or a.get("desc") or str(i) for i, a in enumerate(adapters)] + + def update_ui(): + self._adapters = adapters + self.iface_cb['values'] = names + if names: + self.iface_var.set(names[0]) + self.load_selected_adapter_info(names[0]) + self.after(0, update_ui) + self._append_log("网卡列表刷新完成。\n") + + def on_iface_selected(self, event=None): + name = self.iface_var.get() + self.load_selected_adapter_info(name) + + def load_selected_adapter_info(self, name): + adapter = next((a for a in getattr(self, "_adapters", []) if a.get("name")==name or a.get("desc")==name), None) + if not adapter: + self._append_log(f"未找到网卡信息:{name}\n") + return + + try: + self.ip_entry['var'].set(adapter.get("ip", "")) + self.mask_entry['var'].set(adapter.get("mask", "")) + self.gw_entry['var'].set(adapter.get("gateway", "")) + self.dns1_entry['var'].set(adapter.get("dns1", "")) + self.dns2_entry['var'].set(adapter.get("dns2", "")) + except Exception: + pass + + self.dhcp_var.set(True if str(adapter.get("dhcp", "")).lower() in ("yes","true","是") else False) + self._append_log(f"已加载网卡:{name} IP={adapter.get('ip')} 掩码={adapter.get('mask')} 网关={adapter.get('gateway')} DHCP={adapter.get('dhcp')} MAC={adapter.get('mac')}\n") + + def on_dhcp_toggled(self): + use_dhcp = self.dhcp_var.get() + state = 'disabled' if use_dhcp else 'normal' + for entry in [self.ip_entry, self.mask_entry, self.gw_entry]: + try: + entry['entry'].config(state=state) + except Exception: + try: + entry.config(state=state) + except Exception: + pass + + def on_refresh_info(self): + name = self.iface_var.get() + if not name: + messagebox.showwarning("提示", "请先选择一个网卡") + return + self._append_log(f"读取 {name} 的当前配置信息...\n") + threading.Thread(target=self._refresh_info_thread, args=(name,), daemon=True).start() + + def _refresh_info_thread(self, name): + try: + adapters = self.netmgr.get_all_adapters() + self._adapters = adapters + for a in adapters: + if a.get("name")==name or a.get("desc")==name: + self.after(0, lambda ad=a: self.load_selected_adapter_info(ad.get("name"))) + break + self._append_log("刷新完成。\n") + except Exception as e: + self._append_log(f"读取配置失败: {e}\n") + + def on_apply_clicked(self): + name = self.iface_var.get() + if not name: + messagebox.showwarning("提示", "请选择一个网卡") + return + + def read_field(field): + try: return field['var'].get().strip() + except Exception: + try: return field.get().strip() + except Exception: return "" + + ip = read_field(self.ip_entry) + mask = read_field(self.mask_entry) + gw = read_field(self.gw_entry) + dns1 = read_field(self.dns1_entry) + dns2 = read_field(self.dns2_entry) + + if self.dhcp_var.get(): + if not messagebox.askyesno("确认", f"确定将网卡 [{name}] 切换为 DHCP 模式吗?"): + return + self._set_button_state(False) + threading.Thread(target=self._set_dhcp_thread, args=(name,), daemon=True).start() + return + + if not ip or not mask: + messagebox.showwarning("输入错误", "IP 与掩码不能为空(或勾选 DHCP)") + return + + self._set_button_state(False) + threading.Thread(target=self._set_static_thread, args=(name, ip, mask, gw, dns1, dns2), daemon=True).start() + + def _set_dhcp_thread(self, name): + try: + res = self.netmgr.set_dhcp(name) + self._append_log(f"{res}\n") + messagebox.showinfo("完成", res) + threading.Thread(target=self.refresh_interfaces, daemon=True).start() + except Exception as e: + self._append_log(f"设置 DHCP 失败: {e}\n") + messagebox.showerror("失败", f"设置 DHCP 失败: {e}") + finally: + self._set_button_state(True) + + def _set_static_thread(self, name, ip, mask, gw, dns1, dns2): + try: + res = self.netmgr.set_static_ip(name, ip, mask, gw) + self._append_log(f"{res}\n") + if dns1: + try: + res_dns = self.netmgr.set_dns(name, dns1, dns2) + self._append_log(f"{res_dns}\n") + except Exception as e: + self._append_log(f"设置 DNS 失败: {e}\n") + messagebox.showinfo("完成", "配置已应用(请注意可能需要管理员权限)") + threading.Thread(target=self.refresh_interfaces, daemon=True).start() + except Exception as e: + self._append_log(f"应用静态 IP 失败: {e}\n") + messagebox.showerror("失败", f"应用静态 IP 失败: {e}") + finally: + self._set_button_state(True) + + def on_set_dhcp(self): + name = self.iface_var.get() + if not name: + messagebox.showwarning("提示", "请选择一个网卡") + return + if not messagebox.askyesno("确认", f"确定将网卡 [{name}] 切换为 DHCP 模式吗?"): + return + self._set_button_state(False) + threading.Thread(target=self._set_dhcp_thread, args=(name,), daemon=True).start() + + def _append_log(self, text: str): + try: + self.result_box.after(0, lambda: (self.result_box.insert(tk.END, text), self.result_box.see(tk.END))) + except Exception: + pass diff --git a/core/ui/ui_main.py b/core/ui/ui_main.py index dae6307..539c8ae 100644 --- a/core/ui/ui_main.py +++ b/core/ui/ui_main.py @@ -4,6 +4,7 @@ from tkinter import ttk, filedialog, messagebox from core.ui.basic_ui import BasicUI from core.ui.tab_ping import PingTab from core.ui.tab_telnet import TelnetTab +from core.ui.tab_network import NetworkTab import logging logger = logging.getLogger(__name__) @@ -19,6 +20,7 @@ class MainUI(BasicUI): self.tab_control.pack(expand=1, fill="both") # 实例化各个功能页 self.tabs = { + "网卡配置": NetworkTab(self.tab_control), "Ping测试": PingTab(self.tab_control), "端口扫描服务端": TelnetTab(self.tab_control), }