简体   繁体   English

PyQt5:在线程仍在运行时销毁

[英]PyQt5 : Destroyed while thread is still running

Tried to add exceptions, what should the program (client) do when the server is disconnected.尝试添加异常,当服务器断开时程序(客户端)应该怎么做。

The idea is simple.这个想法很简单。 If the server is turned off - the client should try to connect to the server until the server is turned on.如果服务器关闭 - 客户端应尝试连接到服务器,直到服务器打开。

When server is turn off - program try to connect.当服务器关闭时 - 程序尝试连接。 But when I turned server on, client is connected, and after that connection drops, and in client app I saw that - QThread: Destroyed while thread is still running This is simple example of what I want (minimal reproducible example for client):但是当我打开服务器时,客户端已连接,然后连接断开,在客户端应用程序中我看到 - QThread:在线程仍在运行时被破坏这是我想要的简单示例(客户端的最小可重现示例):

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import socket


class ListeningThread(QtCore.QThread):
    mysignal = QtCore.pyqtSignal(str)
    def __init__(self, server_socket, parent=None):
        QtCore.QThread.__init__(self, parent)
        self.server_socket = server_socket
        self.message = None

    def run(self):
        try:
            while True:
                    self.message = self.server_socket.recv(4096)
                    self.mysignal.emit(self.message.decode('utf-8'))
        except:
             Push()

class Push(QtWidgets.QMainWindow):
    def __init__(self):
        super(Push, self).__init__()
        print('now connecting...')
        self.connect_server()
    def connect_server(self):
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self.server_socket.connect(('127.0.0.1', 5555))
            self.message_monitor = ListeningThread(self.server_socket)
            self.message_monitor.mysignal.connect(self.init_UI)
            self.message_monitor.start()
        except:
            Push()

    def init_UI(self, message):
        print(message)

app =QtWidgets.QApplication([])
application = Push()
sys.exit(app.exec_())

I tried that in ListeningThread:我在 ListeningThread 中尝试过:

 class ListeningThread(QtCore.QThread):
    mysignal = QtCore.pyqtSignal(str)
    def __init__(self, server_socket, parent=None):
        QtCore.QThread.__init__(self, parent)
        self.server_socket = server_socket
        self.message = None

    def run(self):
        try:
            while not self.isInterruptionRequested():
                    self.message = self.server_socket.recv(4096)
                    self.mysignal.emit(self.message.decode('utf-8'))
        except:
            print('error in thread')
            self.requestInterruption()
            self.wait()
            Push()

But the problem is still the same.但问题还是一样。 I think I should close the thread before it starts in Push.connect_server but idk how.我想我应该在 Push.connect_server 开始之前关闭线程,但我不知道如何。

For minimal reproducible example u can use that server:对于最小的可重现示例,您可以使用该服务器:

import socket
import threading

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('127.0.0.1', 5555))
server_socket.listen()
clients = []

def accept_socket():
    while True:
        client_socket, addr = server_socket.accept()
        print(f'connection from {addr}')
        print(client_socket)
        if client_socket not in clients:
            clients.append(client_socket)

def sending_message(clients, data):
    for client_socket in clients:
        try:
            client_socket.send(data.encode("utf-8"))
        except:
            pass

accept_thread = threading.Thread(target= accept_socket)
accept_thread.start()


while True:
    data = input('Enter_message:\n')
    sending_message(clients, data)

The problem is that when an exception occurs you are creating a new "Push" object that has a limited scope since it is a local variable so it will be destroyed, and objects such as the thread will also be destroyed, and that is what it indicates.问题是,当发生异常时,您正在创建一个新的“推送”object,它有一个有限的 scope,因为它是一个局部变量,因此它将被销毁,并且线程等对象也将被销毁,这就是它表示。 the error message.错误信息。

Instead of complicating your life with the handling of threads (IMO they are the last option) you can use a QTcpSocket that allows to handle the sockets in a simple way through signals and that uses the Qt eventloop.您可以使用 QTcpSocket 来通过信号以简单的方式处理 sockets 并使用 Qt 事件循环,而不是使您的生活变得复杂化处理线程(IMO 它们是最后的选择)。

from functools import cached_property
import sys

from PyQt5 import QtCore, QtGui, QtWidgets, QtNetwork


class Client(QtCore.QObject):
    messageChanged = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.socket.stateChanged.connect(self.handle_state_changed)
        self.socket.errorOccurred.connect(self.handle_error_occurred)
        self.socket.readyRead.connect(self.handle_ready_read)

    @cached_property
    def socket(self):
        return QtNetwork.QTcpSocket()

    def try_connect(self):
        self.socket.connectToHost("127.0.0.1", 5555)

    def handle_state_changed(self, state):
        print(f"state: {state}")
        if state == QtNetwork.QAbstractSocket.UnconnectedState:
            print("disconnected")
            QtCore.QTimer.singleShot(1000, self.try_connect)
        elif state == QtNetwork.QAbstractSocket.ConnectedState:
            print("connected")

    def handle_error_occurred(self, error):
        print(f"error code {error}, message: {self.socket.errorString()}")

    def handle_ready_read(self):
        codec = QtCore.QTextCodec.codecForName("UTF-8")
        message = codec.toUnicode(self.socket.readAll())
        self.messageChanged.emit(message)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.client.messageChanged.connect(self.handle_message_changed)
        self.client.try_connect()

    @cached_property
    def client(self):
        return Client()

    def handle_message_changed(self, message):
        print(f"client message: {message}")


def main():

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM