diff --git a/app.log b/app.log index f28a2b5..ab268c5 100644 --- a/app.log +++ b/app.log @@ -234,3 +234,38 @@ 2025-10-31 14:33:40,697 [INFO] 停止由 Ping 2025-10-31 14:49:43,147 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log 2025-10-31 14:49:48,110 [INFO] 停止Ping +2025-10-31 14:58:38,388 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 14:59:33,663 [INFO] 开始Ping www.feixiangdayezhu.top +2025-10-31 14:59:36,241 [INFO] 停止Ping www.feixiangdayezhu.top +2025-10-31 14:59:39,525 [INFO] 开始由 Ping www.feixiangdayezhu.top +2025-10-31 14:59:42,345 [INFO] 停止由 Ping www.feixiangdayezhu.top +2025-10-31 15:01:36,902 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:02:00,585 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:03:20,413 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:04:37,391 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:05:43,467 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:06:28,952 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:07:24,602 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:08:36,439 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:09:05,633 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:11:01,416 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:11:41,046 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:11:54,147 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:11:55,877 [INFO] 开始由 Ping 127.0.0.1 +2025-10-31 15:11:59,513 [INFO] 停止由 Ping 127.0.0.1 +2025-10-31 15:12:01,021 [INFO] 开始由 Ping 127.0.0.1 +2025-10-31 15:12:05,691 [INFO] 停止由 Ping 127.0.0.1 +2025-10-31 15:31:50,086 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:32:43,390 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:33:36,375 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:40:33,765 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:41:13,921 [INFO] 开始由 Ping www.feixiangdayezhu.top +2025-10-31 15:41:20,661 [INFO] 停止由 Ping www.feixiangdayezhu.top +2025-10-31 15:51:03,844 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:51:22,946 [INFO] 开始由 Ping www.feixiangdayezhu.top +2025-10-31 15:51:26,928 [INFO] 停止由 Ping www.feixiangdayezhu.top +2025-10-31 15:56:35,413 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log +2025-10-31 15:56:41,068 [INFO] 开始批量 Ping 192.168.1.1 - 192.168.1.255 +2025-10-31 15:57:02,030 [INFO] 开始由192.168.10.1 批量 Ping 192.168.1.1 - 192.168.1.255 +2025-10-31 15:57:05,860 [INFO] 开始由192.168.10.1 批量 Ping 192.168.1.1 - 192.168.1.255 +2025-10-31 15:57:06,885 [INFO] 停止由192.168.10.1 批量 Ping 192.168.1.1 - 192.168.1.255 diff --git a/core/Function/__pycache__/ping_fun.cpython-313.pyc b/core/Function/__pycache__/ping_fun.cpython-313.pyc index cd4a021..0794e8c 100644 Binary files a/core/Function/__pycache__/ping_fun.cpython-313.pyc and b/core/Function/__pycache__/ping_fun.cpython-313.pyc differ diff --git a/core/Function/ping_fun.py b/core/Function/ping_fun.py index 0d2c20a..4ebb2dc 100644 --- a/core/Function/ping_fun.py +++ b/core/Function/ping_fun.py @@ -1,7 +1,7 @@ import tkinter as tk from tkinter import scrolledtext, messagebox import subprocess -import platform +import concurrent.futures import threading import re @@ -79,3 +79,73 @@ class PingFun: self.result_box.insert(tk.END, stats) self.result_box.see(tk.END) + # ================= 批量 Ping ================= + def start_batch_ping(self, net_prefix, start, end, local_ip=None, callback=None): + """ + 批量 Ping 多个 IP 地址。 + 例如:net_prefix='192.168.1.' start=1 end=254 + """ + self.callback = callback + self.stop_flag = False + self.result_box.delete('1.0', tk.END) + self.result_box.insert(tk.END, f"开始并发 Ping:{net_prefix}{start} - {net_prefix}{end}\n\n") + + # ---- 启动线程池执行 ---- + self.batch_thread = threading.Thread( + target=self._concurrent_batch_ping, args=(net_prefix, start, end, local_ip), daemon=True) + self.batch_thread.start() + + def _ping_one_ip(self, ip, local_ip=None): + """Ping 单个 IP 地址并返回结果""" + if self.stop_flag: + return None + + command = ['ping', ip, '-n', '1', '-w', '1000'] + if local_ip: + command += ['-S', local_ip] + try: + result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + text=True, timeout=2) + if "TTL=" in result.stdout.upper(): + return f"{ip} ✅ 通\n" + else: + return f"{ip} ❌ 不通\n" + except subprocess.TimeoutExpired: + return f"{ip} ⚠️ 超时\n" + except Exception as e: + return f"{ip} 错误: {e}\n" + + def _concurrent_batch_ping(self, net_prefix, start, end, local_ip=None): + """并发执行批量 Ping""" + ip_list = [f"{net_prefix}{i}" for i in range(start, end + 1)] + + # 限制最大并发数,防止系统资源耗尽 + max_workers = min(50, len(ip_list)) + + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + future_to_ip = {executor.submit(self._ping_one_ip, ip, local_ip): ip for ip in ip_list} + + for future in concurrent.futures.as_completed(future_to_ip): + if self.stop_flag: + break + result = future.result() + if result: + self.result_box.insert(tk.END, result) + self.result_box.see(tk.END) + + if not self.stop_flag: + self.result_box.insert(tk.END, "\n并发批量 Ping 完成。\n") + else: + self.result_box.insert(tk.END, "\n批量 Ping 已停止。\n") + self.result_box.see(tk.END) + if self.callback: + self.callback() + + def stop_batch_ping(self): + """停止并发批量 ping""" + if not self.batch_thread or not self.batch_thread.is_alive(): + messagebox.showinfo("提示", "当前没有正在运行的批量 Ping。") + return + self.stop_flag = True + self.result_box.insert(tk.END, "\n正在尝试停止批量 Ping...\n") + self.result_box.see(tk.END) \ No newline at end of file diff --git a/core/ui/__pycache__/basic_ui.cpython-313.pyc b/core/ui/__pycache__/basic_ui.cpython-313.pyc index c579c2b..32df0a6 100644 Binary files a/core/ui/__pycache__/basic_ui.cpython-313.pyc and b/core/ui/__pycache__/basic_ui.cpython-313.pyc differ diff --git a/core/ui/__pycache__/tab_ping.cpython-313.pyc b/core/ui/__pycache__/tab_ping.cpython-313.pyc index 92527ef..7a18b90 100644 Binary files a/core/ui/__pycache__/tab_ping.cpython-313.pyc and b/core/ui/__pycache__/tab_ping.cpython-313.pyc differ diff --git a/core/ui/basic_ui.py b/core/ui/basic_ui.py index 20b8c89..e4cd38f 100644 --- a/core/ui/basic_ui.py +++ b/core/ui/basic_ui.py @@ -88,7 +88,7 @@ class BasicUI: def add_button( self, parent, button_text, row, col=0, command="", - label_width=8, entry_width=20, colspan=1, sticky='w' + label_width=8, width=5, colspan=1, sticky='w' ): """ 添加一个按钮,并返回 (StringVar, Frame) 以便后续控制。 @@ -96,14 +96,14 @@ class BasicUI: - button_text: 按钮文本 - row, col: 放置在父容器的 grid 行列 - command: 调用的函数 - - entry_width: 输入框宽度 + - width: 输入框宽度 - colspan: 该组控件在父容器上跨越的列数 - sticky: 对齐方式(默认左对齐) """ group_frame = ttk.Frame(parent) group_frame.grid(row=row, column=col, columnspan=colspan, sticky=sticky, padx=5, pady=3) - btn = ttk.Button(group_frame, text=button_text, command=command) + btn = ttk.Button(group_frame, text=button_text, command=command, width=width) btn.grid(row=0, column=0, sticky='w') return { "frame": group_frame, diff --git a/core/ui/tab_ping.py b/core/ui/tab_ping.py index 9355c8f..7ce2e5d 100644 --- a/core/ui/tab_ping.py +++ b/core/ui/tab_ping.py @@ -15,28 +15,31 @@ class PingTab(ttk.Frame, BasicUI): def ping_ui(self): """ping界面布局""" - self.create_allIP_section() self.create_assignIP_section() + self.create_batchIP_section() self.create_outputping_section() # --------------------------------------UI界面布局函数-------------------------------------- - def create_allIP_section(self): - # 区域标签 - frame = ttk.LabelFrame(self, text="PING 目标IP") - frame.pack(side='top', fill='x', padx=10, pady=5) - - self.entry_allIP = self.add_input(frame, "目标IP", row=0, col=0) - self.allIP_startPing = self.add_button(frame, "开始ping", row=0, col=1, command=self.btn_allIP_startPing) - self.allIP_stopPing = self.add_button(frame, "停止ping", row=0, col=2, command=self.btn_allIP_stopPing) - def create_assignIP_section(self): # 区域标签 - frame = ttk.LabelFrame(self, text="指定IP PING 目标IP") + frame = ttk.LabelFrame(self, text="指定地址 Ping 目标地址") frame.pack(side='top', fill='x', padx=10, pady=5) self.entry_assignIP_A = self.add_input(frame, "本地IP", row=0, col=0) - self.entry_assignIP_B = self.add_input(frame, "目标IP", row=0, col=1) - self.assignIP_startPing = self.add_button(frame, "开始ping", row=0, col=2, command=self.btn_assignIP_startPing) - self.assignIP_stopPing = self.add_button(frame, "停止ping", row=0, col=3, command=self.btn_assignIP_stopPing) + self.entry_assignIP_B = self.add_input(frame, "目标IP", row=0, col=1, inivar="127.0.0.1") + self.assignIP_startPing = self.add_button(frame, "开始", row=0, col=2, command=self.btn_assignIP_startPing) + self.assignIP_stopPing = self.add_button(frame, "停止", row=0, col=3, command=self.btn_assignIP_stopPing) + + def create_batchIP_section(self): + # 区域标签 + frame = ttk.LabelFrame(self, text="指定地址 Ping 批量地址") + frame.pack(side='top', fill='x', padx=10, pady=5) + + self.entry_batchIP_A = self.add_input(frame, "本地IP", row=0, col=0) + self.entry_batchIP_B = self.add_input(frame, "C类网段", row=0, col=1, inivar="192.168.1.", entry_width=15) + self.entry_batchIP_B_begin = self.add_input(frame, "起始地址", row=0, col=2, inivar="1", entry_width=5) + self.entry_batchIP_B_end = self.add_input(frame, "结束地址", row=0, col=3, inivar="255", entry_width=5) + self.batchIP_startPing = self.add_button(frame, "开始", row=0, col=4, command=self.btn_batchIP_startPing) + self.batchIP_stopPing = self.add_button(frame, "停止", row=0, col=5, command=self.btn_batchIP_stopPing) def create_outputping_section(self): # 区域标签 @@ -46,25 +49,9 @@ class PingTab(ttk.Frame, BasicUI): self.result_box = scrolledtext.ScrolledText(frame, width=100, height=20) self.result_box.pack(pady=10) # --------------------------------------按钮回调函数-------------------------------------- - def btn_allIP_startPing(self): - if not self.entry_allIP['var'].get(): - messagebox.showwarning("输入错误", "请输入IP或域名!") - return - logger.info(f"开始Ping {self.entry_allIP['var'].get()}") - self.ping_fun.strat_ping(self.entry_allIP['var'].get(), callback=self.allIP_ping_callback) - self.allIP_startPing['btn'].config(state='disabled') - - def btn_allIP_stopPing(self): - logger.info(f"停止Ping {self.entry_allIP['var'].get()}") - self.ping_fun.stop_ping() - self.allIP_startPing['btn'].config(state='normal') - - def allIP_ping_callback(self): - self.allIP_startPing['btn'].config(state='normal') - def btn_assignIP_startPing(self): if not self.entry_assignIP_B['var'].get(): - messagebox.showwarning("输入错误", "请输入IP或域名!") + messagebox.showwarning("输入错误", "请输入目标IP或域名!") return logger.info(f"开始由{self.entry_assignIP_A['var'].get()} Ping {self.entry_assignIP_B['var'].get()}") self.ping_fun.strat_ping(self.entry_assignIP_B['var'].get(),local_ip=self.entry_assignIP_A['var'].get(), @@ -79,6 +66,53 @@ class PingTab(ttk.Frame, BasicUI): def assignIP_ping_callback(self): self.assignIP_startPing['btn'].config(state='normal') + def btn_batchIP_startPing(self): + net_prefix = self.entry_batchIP_B['var'].get() + start = self.entry_batchIP_B_begin['var'].get() + end = self.entry_batchIP_B_end['var'].get() + local_ip = self.entry_batchIP_A['var'].get() + # ========= 输入参数检查 ========= + if not net_prefix or start is None or end is None: + messagebox.showwarning("输入错误", "请输入完整的网段、起始地址和结束地址!") + return + try: + start = int(start) + end = int(end) + except ValueError: + messagebox.showwarning("输入错误", "起始地址和结束地址必须是整数!") + return + if start < 1 or end > 255: + messagebox.showwarning("输入错误", "起始地址最小为1,结束地址最大为255!") + return + if start > end: + messagebox.showwarning("输入错误", "起始地址不能大于结束地址!") + return + if not net_prefix.endswith('.'): + messagebox.showwarning("输入错误", "网段必须以 '.' 结尾,例如:192.168.1.") + return + if local_ip == "": + logger.info(f"开始批量 Ping {net_prefix}{start} - {net_prefix}{end}") + else: + logger.info(f"开始由{local_ip} 批量 Ping {net_prefix}{start} - {net_prefix}{end}") + + self.ping_fun.start_batch_ping(net_prefix, start, end, local_ip=local_ip, callback=self.batchIP_ping_callback) + self.batchIP_startPing['btn'].config(state='disabled') + + def btn_batchIP_stopPing(self): + net_prefix = self.entry_batchIP_B['var'].get() + start = self.entry_batchIP_B_begin['var'].get() + end = self.entry_batchIP_B_end['var'].get() + local_ip = self.entry_batchIP_A['var'].get() + if local_ip == "": + logger.info(f"停止批量 Ping {net_prefix}{start} - {net_prefix}{end}") + else: + logger.info(f"停止由{local_ip} 批量 Ping {net_prefix}{start} - {net_prefix}{end}") + self.ping_fun.stop_batch_ping() + self.batchIP_startPing['btn'].config(state='normal') + + def batchIP_ping_callback(self): + self.batchIP_startPing['btn'].config(state='normal') +