为了账号安全,请及时绑定邮箱和手机立即绑定

单击按钮后程序停止响应

单击按钮后程序停止响应

胡说叔叔 2022-06-28 17:35:34
我正在尝试制作我的第一个程序,一个显示远程服务器上所有开放端口的端口扫描器,我已经让它在 CLI 中工作(感谢互联网),但决定制作一个 GUI(Qt5)它。我希望 textbox2 在输入 IP 地址并单击“扫描!”后输出所有打开的端口,显然程序在单击后不会崩溃。这是复制问题的相关代码from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QPushButton, QAction, QLineEdit, QMessageBox, QPlainTextEdit, QVBoxLayout, QLabelfrom PyQt5.QtGui import QIconfrom PyQt5.QtCore import pyqtSlot, Qtimport socketimport timeimport sysclass App(QMainWindow):    def __init__(self):        super().__init__()        self.title = 'PPort'        self.left = 10        self.top = 10        self.width = 800        self.height = 400        self.initUI()    def initUI(self):        self.setWindowTitle(self.title)        self.setGeometry(self.left, self.top, self.width, self.height)        self.label = QLabel('Enter Target Address:', self)        self.label.move(50, -110)        self.label.resize(300, 300)        self.label2 = QLabel('Output:', self)        self.label2.move(50, 80)        self.label2.resize(300, 300)        self.textbox = QLineEdit(self)        self.textbox.move(50, 60)        self.textbox.resize(540, 30)        self.textbox2 = QPlainTextEdit(self)        self.textbox2.move(50, 250)        self.textbox2.resize(700, 100)        self.textbox2.setReadOnly(True)        self.button = QPushButton('Scan!', self)        self.button.move(620, 60)        self.button.clicked.connect(self.on_click)        self.show()textbox2中没有显示错误,令我感到奇怪的是,即使我self.textbox2.appendPlainText用print()替换,它仍然没有在vscode终端中输出任何错误消息。但是,输入无效的 IP 地址会显示 gaierror(无法解析主机),而不是在 textbox2 中,而是在终端中,与输入有效 IP 地址(8.8.8.8、192.168.0.1)时它总是崩溃的情况相比. 我怀疑我使用 if/for/try 错误地使其循环,但我真的看不出我做错了什么,因为我几乎不知道我作为新手在做什么。
查看完整描述

1 回答

?
喵喔喔

TA贡献1735条经验 获得超5个赞

for-loop 或 sleep 等耗时的任务会阻塞 GUI 事件循环,导致窗口冻结。在这些情况下,解决方案是在另一个线程中执行该任务并通过信号在线程之间发送信息


import sys

import time

import socket

from functools import partial


from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QThread, QTimer

from PyQt5.QtWidgets import (

    QApplication,

    QGridLayout,

    QLabel,

    QLineEdit,

    QMainWindow,

    QPlainTextEdit,

    QPushButton,

    QWidget,

)



class SocketWorker(QObject):

    messageChanged = pyqtSignal(str)


    @pyqtSlot(str)

    def start_task(self, ip):

        socket.gethostbyname(ip)

        try:

            for port in range(0, 65536):

                socketprofile = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

                result = socketprofile.connect_ex((ip, port))

                if result == 0:

                    self.messageChanged.emit("Port {} Is open".format(port))

                socketprofile.close()

        except socket.gaierror:

            self.messageChanged.emit("Hostname could not be resolved")

            time.sleep(5)

            sys.exit()

        except socket.error:

            self.messageChanged.emit("Couldn't connect to server")

            time.sleep(5)

            sys.exit()



class App(QMainWindow):

    def __init__(self):

        super().__init__()

        self.title = "PPort"

        self.left = 10

        self.top = 10

        self.width = 800

        self.height = 400

        self.initUI()


    def initUI(self):

        self.setWindowTitle(self.title)

        self.setGeometry(self.left, self.top, self.width, self.height)


        self.textbox = QLineEdit()

        self.button = QPushButton("Scan!")

        self.textbox2 = QPlainTextEdit(readOnly=True)


        central_widget = QWidget()

        self.setCentralWidget(central_widget)

        grid_layout = QGridLayout(central_widget)

        grid_layout.addWidget(QLabel("Enter Target Address:"), 0, 0)

        grid_layout.addWidget(self.textbox, 1, 0)

        grid_layout.addWidget(self.button, 1, 1)

        grid_layout.addWidget(QLabel("Output:"), 2, 0)

        grid_layout.addWidget(self.textbox2, 3, 0, 1, 2)


        self.button.clicked.connect(self.on_click)


        thread = QThread(self)

        thread.start()

        self.socker_worker = SocketWorker()

        self.socker_worker.moveToThread(thread)

        self.socker_worker.messageChanged.connect(self.textbox2.appendPlainText)


    @pyqtSlot()

    def on_click(self):

        textboxValue = self.textbox.text()

        wrapper = partial(self.socker_worker.start_task, textboxValue)

        QTimer.singleShot(0, wrapper)



if __name__ == "__main__":

    app = QApplication(sys.argv)

    ex = App()

    ex.show()

    sys.exit(app.exec_())


查看完整回答
反对 回复 2022-06-28
  • 1 回答
  • 0 关注
  • 129 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信