trae开发的win10端口占用检测工具

笔记哥 / 05-13 / 40点赞 / 0评论 / 436阅读
### 前言 * * * 首先,字节开发的工具:https://www.trae.com.cn/ 以下代码均由此工具生成。 linux 中可以使用 `lsof -i:端口号` 查看端口占用进程,并使用`kill`指令杀死进程,但是对于不熟悉windows命令行的同学, 如果运行代码时,一直提示某个端口被占用,使用`netstat -ano|findstr LISTEN` 虽然也可以查到端口占用进程,但是`taskkill` 指令还是挺麻烦的。 下面是用trae开发的基于python wxpython库的端口占用检测界面工具。 ### 正文 * * * 1. 主程序 port\_monitor.py ```python import wx import subprocess import re class PortMonitorFrame(wx.Frame): def __init__(self, parent, title): super(PortMonitorFrame, self).__init__(parent, title=title, size=(600, 400)) self.InitUI() self.Centre() self.is_scanning = False def InitUI(self): panel = wx.Panel(self) vbox = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) self.port_input = wx.TextCtrl(panel) hbox1.Add(wx.StaticText(panel, label='端口号:'), flag=wx.RIGHT, border=8) hbox1.Add(self.port_input, proportion=1) hbox2 = wx.BoxSizer(wx.HORIZONTAL) self.check_btn = wx.Button(panel, label='检测端口占用') self.kill_btn = wx.Button(panel, label='终止占用进程') self.check_btn.Bind(wx.EVT_BUTTON, self.on_check_port) self.kill_btn.Bind(wx.EVT_BUTTON, self.on_kill_process) hbox2.Add(self.check_btn, flag=wx.RIGHT, border=8) hbox2.Add(self.kill_btn) self.result_list = wx.ListCtrl(panel, style=wx.LC_REPORT) self.result_list.InsertColumn(0, 'PID', width=100) self.result_list.InsertColumn(1, '程序名称', width=200) self.result_list.InsertColumn(2, '状态', width=150) self.result_list.InsertColumn(3, '是否为主程序', width=100) self.result_list.InsertColumn(4, '程序路径', width=250) vbox.Add(hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10) vbox.Add(hbox2, flag=wx.EXPAND|wx.ALL, border=10) vbox.Add(self.result_list, proportion=1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, border=10) panel.SetSizer(vbox) def on_check_port(self, event): port = self.port_input.GetValue().strip() if not port.isdigit(): wx.MessageBox('请输入有效的端口号', '错误', wx.ICON_ERROR) return if self.is_scanning: wx.MessageBox('扫描正在进行中', '提示', wx.ICON_INFORMATION) return self.result_list.DeleteAllItems() self.is_scanning = True wx.CallAfter(self.check_btn.Enable, False) def scan_task(): try: startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW output = subprocess.check_output(['netstat', '-ano'], text=True, stderr=subprocess.STDOUT, startupinfo=startupinfo) pattern = re.compile(r'TCP\s+.*?:{}\s+.*?\s+(\d+)'.format(port)) pids = pattern.findall(output) if not pids: wx.CallAfter(wx.MessageBox, '端口未被占用', '提示', wx.ICON_INFORMATION) else: for pid in set(pids): if not self.is_scanning: # 扫描被中断时退出循环 break startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW task_info = subprocess.check_output(['tasklist', '/fi', f'pid eq {pid}'], text=True, stderr=subprocess.STDOUT, startupinfo=startupinfo) proc_name = re.search(r'(.+?)\s+\d+\s+Console', task_info) proc_name = proc_name.group(1).strip() if proc_name else '未知程序' # 解析netstat输出获取PID对应的连接状态 pattern_detail = re.compile(r'TCP\s+.*?:{}\s+.*?\s+(\S+)\s+({})'.format(port, pid)) status_match = pattern_detail.search(output) is_listening = status_match.group(1) == 'LISTENING' if status_match else False def update_ui(pid, proc_name, is_listening, proc_path): index = self.result_list.InsertItem(self.result_list.GetItemCount(), pid) self.result_list.SetItem(index, 1, proc_name) self.result_list.SetItem(index, 2, '运行中') self.result_list.SetItem(index, 3, '是' if is_listening else '') self.result_list.SetItem(index, 4, proc_path) if is_listening: self.result_list.SetItemTextColour(index, wx.RED) # 获取程序路径(使用wmic命令) try: proc_path_output = subprocess.check_output(['wmic', 'process', 'where', f'processid={pid}', 'get', 'executablepath'], text=True, stderr=subprocess.STDOUT, startupinfo=startupinfo) proc_path_match = re.search(r'ExecutablePath\s+(.+?)\s*$', proc_path_output, re.MULTILINE) proc_path = proc_path_match.group(1).strip() if proc_path_match else '未知路径' except: proc_path = '未知路径' wx.CallAfter(update_ui, pid, proc_name, is_listening, proc_path) except subprocess.CalledProcessError as e: wx.CallAfter(wx.MessageBox, f'执行命令失败:{e.output}', '错误', wx.ICON_ERROR) finally: self.is_scanning = False wx.CallAfter(self.check_btn.Enable, True) import threading threading.Thread(target=scan_task, daemon=True).start() def on_kill_process(self, event): if self.is_scanning: wx.MessageBox('扫描未完成,请稍后', '提示', wx.ICON_INFORMATION) return selected = self.result_list.GetFirstSelected() if selected == -1: wx.MessageBox('请选择要终止的进程', '提示', wx.ICON_INFORMATION) return pid = self.result_list.GetItemText(selected) try: startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW output = subprocess.check_output(['taskkill', '/F', '/PID', pid], text=True, stderr=subprocess.STDOUT, startupinfo=startupinfo) self.result_list.DeleteItem(selected) wx.MessageBox('进程终止成功', '提示', wx.ICON_INFORMATION) except subprocess.CalledProcessError as e: wx.MessageBox(f'终止进程失败:{e.output}', '错误', wx.ICON_ERROR) if __name__ == '__main__': app = wx.App() frame = PortMonitorFrame(None, '端口监控工具') frame.Show() app.MainLoop() ``` 1. 编译成二进制脚本 这里使用了 nuitka 工具,将py脚本编译成c++的可执行程序。也可以使用 pyinstaller (pyinstaller 编译成的程序会在用户目录留下缓存文件) ```bash pip install nuitka ``` 批处理文件 build.bat ```bat @echo off nuitka --standalone --onefile --windows-console-mode=disable port_monitor.py echo 打包完成,可执行文件在dist目录下 pause ``` 运行后,生成 `port_monitor.exe` 1. 运行 直接python脚本运行 ```python python port_monitor.py ``` exe运行 ```bash port_monitor.exe ``` 运行效果展示: ![image](https://cdn.res.knowhub.vip/c/2505/13/3cfd840b.png?G1cAAMTW3Dgp8AFl22gDdWfqnTYDFmkElRLW6917rpvo%2bwMMzU%2bvbcT68JvaRpBcrqaFwDA2pCCHQBxmrgnMwiw4S549AA%3d%3d)