This commit is contained in:
2025-10-31 15:57:36 +08:00
parent e05a7c02df
commit 0a646bb017
7 changed files with 174 additions and 35 deletions
+35
View File
@@ -234,3 +234,38 @@
2025-10-31 14:33:40,697 [INFO] 停止由 Ping 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:43,147 [INFO] 日志系统初始化完成,日志文件路径:E:\Git\Network-tools\app.log
2025-10-31 14:49:48,110 [INFO] 停止Ping 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
Binary file not shown.
+71 -1
View File
@@ -1,7 +1,7 @@
import tkinter as tk import tkinter as tk
from tkinter import scrolledtext, messagebox from tkinter import scrolledtext, messagebox
import subprocess import subprocess
import platform import concurrent.futures
import threading import threading
import re import re
@@ -79,3 +79,73 @@ class PingFun:
self.result_box.insert(tk.END, stats) self.result_box.insert(tk.END, stats)
self.result_box.see(tk.END) 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)
Binary file not shown.
Binary file not shown.
+3 -3
View File
@@ -88,7 +88,7 @@ class BasicUI:
def add_button( def add_button(
self, parent, button_text, self, parent, button_text,
row, col=0, command="", 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) 以便后续控制。 添加一个按钮,并返回 (StringVar, Frame) 以便后续控制。
@@ -96,14 +96,14 @@ class BasicUI:
- button_text: 按钮文本 - button_text: 按钮文本
- row, col: 放置在父容器的 grid 行列 - row, col: 放置在父容器的 grid 行列
- command: 调用的函数 - command: 调用的函数
- entry_width: 输入框宽度 - width: 输入框宽度
- colspan: 该组控件在父容器上跨越的列数 - colspan: 该组控件在父容器上跨越的列数
- sticky: 对齐方式(默认左对齐) - sticky: 对齐方式(默认左对齐)
""" """
group_frame = ttk.Frame(parent) group_frame = ttk.Frame(parent)
group_frame.grid(row=row, column=col, columnspan=colspan, sticky=sticky, padx=5, pady=3) 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') btn.grid(row=0, column=0, sticky='w')
return { return {
"frame": group_frame, "frame": group_frame,
+65 -31
View File
@@ -15,28 +15,31 @@ class PingTab(ttk.Frame, BasicUI):
def ping_ui(self): def ping_ui(self):
"""ping界面布局""" """ping界面布局"""
self.create_allIP_section()
self.create_assignIP_section() self.create_assignIP_section()
self.create_batchIP_section()
self.create_outputping_section() self.create_outputping_section()
# --------------------------------------UI界面布局函数-------------------------------------- # --------------------------------------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): 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) 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_A = self.add_input(frame, "本地IP", row=0, col=0)
self.entry_assignIP_B = self.add_input(frame, "目标IP", row=0, col=1) 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, "开始ping", row=0, col=2, command=self.btn_assignIP_startPing) self.assignIP_startPing = self.add_button(frame, "开始", 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.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): 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 = scrolledtext.ScrolledText(frame, width=100, height=20)
self.result_box.pack(pady=10) 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): def btn_assignIP_startPing(self):
if not self.entry_assignIP_B['var'].get(): if not self.entry_assignIP_B['var'].get():
messagebox.showwarning("输入错误", "请输入IP或域名!") messagebox.showwarning("输入错误", "请输入目标IP或域名!")
return return
logger.info(f"开始由{self.entry_assignIP_A['var'].get()} Ping {self.entry_assignIP_B['var'].get()}") 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(), 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): def assignIP_ping_callback(self):
self.assignIP_startPing['btn'].config(state='normal') 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')