Python實(shí)現(xiàn)美化版端口進(jìn)程管理工具
1. 簡(jiǎn)介
一個(gè)基于端口管理和進(jìn)程管理的GUI工具,它可以顯示當(dāng)前系統(tǒng)上所有開(kāi)放的端口信息,并且允許用戶(hù)對(duì)選中的進(jìn)程進(jìn)行操作(如結(jié)束進(jìn)程、定位進(jìn)程文件夾路徑、復(fù)制相關(guān)信息到剪貼板等)。
詳細(xì)信息可參考原文信息:基于Python編寫(xiě)端口進(jìn)程管理工具
2. 運(yùn)行效果



3. 相關(guān)源碼
import sys
import psutil
import os
import pyperclip
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QMenu, QAction, QComboBox, QLineEdit, QPushButton, QMessageBox, QHeaderView
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
# 獲取本機(jī)所有開(kāi)放的端口及對(duì)應(yīng)的進(jìn)程信息
def get_open_ports():
open_ports = []
for conn in psutil.net_connections(kind='inet'):
if conn.status != 'LISTEN':
continue
pid = conn.pid
if conn.type == 1: # TCP協(xié)議
protocol = 'TCP'
elif conn.type == 2: # UDP協(xié)議
protocol = 'UDP'
else:
protocol = 'N/A'
try:
process = psutil.Process(pid)
process_name = process.name()
exe_path = process.exe()
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
process_name = "N/A"
exe_path = "N/A"
open_ports.append({
'Port': conn.laddr.port,
'PID': pid,
'Process Name': process_name,
'Protocol': protocol,
'Path': exe_path
})
return open_ports
# 根據(jù)端口號(hào)查詢(xún)對(duì)應(yīng)進(jìn)程的信息
def search_by_port(port):
open_ports = get_open_ports()
for port_info in open_ports:
if port_info['Port'] == port:
return port_info
return None
# 根據(jù)進(jìn)程名稱(chēng)查詢(xún)對(duì)應(yīng)的端口信息
def search_by_process_name(name):
open_ports = get_open_ports()
result = []
for port_info in open_ports:
if name.lower() in port_info['Process Name'].lower():
result.append(port_info)
return result
# 根據(jù)PID查詢(xún)對(duì)應(yīng)的端口信息
def search_by_pid(pid):
open_ports = get_open_ports()
for port_info in open_ports:
if port_info['PID'] == pid:
return port_info
return None
# 結(jié)束進(jìn)程
def kill_process(pid):
try:
process = psutil.Process(pid)
process.terminate() # 發(fā)送 terminate 信號(hào)
process.wait() # 等待進(jìn)程結(jié)束
return True
except (psutil.NoSuchProcess, psutil.AccessDenied):
return False
# 定位進(jìn)程文件夾路徑
def open_process_folder(exe_path):
if exe_path and os.path.exists(exe_path):
folder_path = os.path.dirname(exe_path)
os.startfile(folder_path) # 打開(kāi)文件夾
return True
return False
# 復(fù)制到剪貼板的功能
def copy_to_clipboard(text):
pyperclip.copy(text) # 使用 pyperclip 庫(kù)復(fù)制文本
class PortProcessManager(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("端口進(jìn)程管理工具")
self.setWindowIcon(QIcon(os.path.join(os.getcwd(), 'icon.ico')))
self.setGeometry(100, 100, 900, 600)
#self.setWindowOpacity(0.8) # 設(shè)置窗口透明度為0.8
# 主窗口布局
self.main_widget = QWidget()
self.setCentralWidget(self.main_widget)
layout = QVBoxLayout(self.main_widget)
# 搜索框布局
search_layout = QHBoxLayout()
self.search_type_combo = QComboBox()
self.search_type_combo.addItems(["端口號(hào)", "進(jìn)程名稱(chēng)", "PID"])
self.search_type_combo.setCurrentIndex(0)
search_layout.addWidget(self.search_type_combo)
self.search_input = QLineEdit()
search_layout.addWidget(self.search_input)
self.search_button = QPushButton("查 詢(xún)")
self.search_button.clicked.connect(self.search)
search_layout.addWidget(self.search_button)
self.refresh_button = QPushButton("刷新列表")
self.refresh_button.clicked.connect(self.refresh_list)
search_layout.addWidget(self.refresh_button)
layout.addLayout(search_layout)
# 表格展示
self.table = QTableWidget()
self.table.setColumnCount(5)
self.table.setHorizontalHeaderLabels(["PID", "協(xié)議", "端口", "進(jìn)程名稱(chēng)", "相關(guān)路徑"])
self.table.setEditTriggers(QTableWidget.NoEditTriggers) # 禁止編輯
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # 列寬自適應(yīng)
layout.addWidget(self.table)
# 右鍵菜單
self.table.setContextMenuPolicy(Qt.CustomContextMenu)
self.table.customContextMenuRequested.connect(self.open_right_menu)
# 設(shè)置樣式
self.set_styles()
# 初始化數(shù)據(jù)
self.refresh_list()
def set_styles(self):
# 設(shè)置字體為 "Segoe UI"
style = """
* {
font-family: "Segoe UI";
}
QPushButton {
background-color: #2dd8e1;
color: white;
border: 1px solid #00a7c3;
padding: 5px;
}
QHeaderView::section {
background-color: #2dd8e1;
color: white;
padding: 5px;
}
"""
self.setStyleSheet(style)
def refresh_list(self):
self.table.setRowCount(0)
open_ports = get_open_ports()
if not open_ports:
QMessageBox.information(self, "沒(méi)有找到端口", "沒(méi)有開(kāi)放的端口或無(wú)法獲取端口信息。")
return
for port_info in open_ports:
row_position = self.table.rowCount()
self.table.insertRow(row_position)
self.table.setItem(row_position, 0, QTableWidgetItem(str(port_info['PID'])))
self.table.setItem(row_position, 1, QTableWidgetItem(port_info['Protocol']))
self.table.setItem(row_position, 2, QTableWidgetItem(str(port_info['Port'])))
self.table.setItem(row_position, 3, QTableWidgetItem(port_info['Process Name']))
self.table.setItem(row_position, 4, QTableWidgetItem(port_info['Path']))
def search(self):
search_value = self.search_input.text()
search_type = self.search_type_combo.currentText()
if not search_value:
QMessageBox.warning(self, "輸入錯(cuò)誤", "請(qǐng)輸入查詢(xún)內(nèi)容!")
return
self.table.setRowCount(0)
if search_type == "端口號(hào)":
try:
port = int(search_value)
port_info = search_by_port(port)
if port_info:
self.add_row(port_info)
else:
QMessageBox.information(self, "未找到", f"未找到端口 {port} 對(duì)應(yīng)的進(jìn)程。")
except ValueError:
QMessageBox.warning(self, "輸入錯(cuò)誤", "請(qǐng)輸入有效的端口號(hào)。")
elif search_type == "進(jìn)程名稱(chēng)":
result = search_by_process_name(search_value)
if result:
for port_info in result:
self.add_row(port_info)
else:
QMessageBox.information(self, "未找到", f"未找到進(jìn)程名稱(chēng)包含 {search_value} 的記錄。")
elif search_type == "PID":
try:
pid = int(search_value)
port_info = search_by_pid(pid)
if port_info:
self.add_row(port_info)
else:
QMessageBox.information(self, "未找到", f"未找到PID {pid} 對(duì)應(yīng)的進(jìn)程。")
except ValueError:
QMessageBox.warning(self, "輸入錯(cuò)誤", "請(qǐng)輸入有效的PID。")
def add_row(self, port_info):
row_position = self.table.rowCount()
self.table.insertRow(row_position)
self.table.setItem(row_position, 0, QTableWidgetItem(str(port_info['PID'])))
self.table.setItem(row_position, 1, QTableWidgetItem(port_info['Protocol']))
self.table.setItem(row_position, 2, QTableWidgetItem(str(port_info['Port'])))
self.table.setItem(row_position, 3, QTableWidgetItem(port_info['Process Name']))
self.table.setItem(row_position, 4, QTableWidgetItem(port_info['Path']))
def open_right_menu(self, pos):
selected_item = self.table.itemAt(pos)
if selected_item:
row = selected_item.row()
pid = self.table.item(row, 0).text()
port = self.table.item(row, 2).text()
process_name = self.table.item(row, 3).text()
exe_path = self.table.item(row, 4).text()
menu = QMenu(self)
kill_action = QAction("結(jié)束進(jìn)程", self)
kill_action.triggered.connect(lambda: self.kill_process(int(pid)))
menu.addAction(kill_action)
folder_action = QAction("定位進(jìn)程文件夾路徑", self)
folder_action.triggered.connect(lambda: self.open_folder(exe_path))
menu.addAction(folder_action)
copy_pid_action = QAction("復(fù)制PID", self)
copy_pid_action.triggered.connect(lambda: copy_to_clipboard(pid))
menu.addAction(copy_pid_action)
copy_port_action = QAction("復(fù)制端口號(hào)", self)
copy_port_action.triggered.connect(lambda: copy_to_clipboard(port))
menu.addAction(copy_port_action)
copy_process_action = QAction("復(fù)制進(jìn)程名稱(chēng)", self)
copy_process_action.triggered.connect(lambda: copy_to_clipboard(process_name))
menu.addAction(copy_process_action)
copy_path_action = QAction("復(fù)制相關(guān)路徑", self)
copy_path_action.triggered.connect(lambda: copy_to_clipboard(exe_path))
menu.addAction(copy_path_action)
menu.exec_(self.table.viewport().mapToGlobal(pos))
def kill_process(self, pid):
if kill_process(pid):
QMessageBox.information(self, "結(jié)束進(jìn)程", f"進(jìn)程 (PID: {pid}) 已被成功結(jié)束。")
else:
QMessageBox.warning(self, "錯(cuò)誤", "無(wú)法結(jié)束該進(jìn)程,可能沒(méi)有權(quán)限。")
def open_folder(self, exe_path):
if open_process_folder(exe_path):
QMessageBox.information(self, "打開(kāi)文件夾", "已成功定位進(jìn)程文件夾。")
else:
QMessageBox.warning(self, "錯(cuò)誤", "無(wú)法找到進(jìn)程文件路徑。")
def keyPressEvent(self, event):
if event.key() == Qt.Key_Return: # 檢測(cè)到回車(chē)鍵
self.search() # 執(zhí)行查詢(xún)操作
else:
super().keyPressEvent(event)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = PortProcessManager()
window.show()
sys.exit(app.exec_())
到此這篇關(guān)于Python實(shí)現(xiàn)美化版端口進(jìn)程管理工具的文章就介紹到這了,更多相關(guān)Python端口進(jìn)程管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實(shí)現(xiàn)生成簡(jiǎn)單的Makefile文件代碼示例
這篇文章主要介紹了Python實(shí)現(xiàn)生成簡(jiǎn)單的Makefile文件代碼示例,本文給出了兩段實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-03-03
在Python中使用sort()方法進(jìn)行排序的簡(jiǎn)單教程
這篇文章主要介紹了在Python中使用sort()方法進(jìn)行排序的簡(jiǎn)單教程,是Python學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-05-05
Python數(shù)據(jù)可視化完全指南之Matplotlib+Seaborn+Plotly用法詳解
本文詳細(xì)介紹了Python數(shù)據(jù)可視化的三大主流庫(kù):Matplotlib、Seaborn與Plotly,涵蓋折線圖、柱狀圖、散點(diǎn)圖等多種圖表類(lèi)型及美化技巧,希望幫助大家全面掌握數(shù)據(jù)可視化技能,提升數(shù)據(jù)呈現(xiàn)效果2026-05-05
使用Django和Python創(chuàng)建Json response的方法
下面小編就為大家分享一篇使用Django和Python創(chuàng)建Json response的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
Elasticsearch映射字段數(shù)據(jù)類(lèi)型及管理
這篇文章主要介紹了Elasticsearch映射字段數(shù)據(jù)類(lèi)型及管理的講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
Python使用PyFiglet實(shí)現(xiàn)終端輸出炫酷的ASCII藝術(shù)字效果
PyFiglet是一個(gè)基于Python的純文本到ASCII藝術(shù)字轉(zhuǎn)換工具,它實(shí)現(xiàn)了FIGlet的完整功能,本文給大家介紹了Python如何使用PyFiglet實(shí)現(xiàn)終端輸出炫酷的ASCII藝術(shù)字效果,需要的朋友可以參考下2025-12-12
pytorch常用函數(shù)之torch.randn()解讀
這篇文章主要介紹了pytorch常用函數(shù)之torch.randn()解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02

