QWebSocket客户端无法连接到未创建时不监听的QWebSocketServer,也无法在服务器后续开始监听时连接

1 投票
1 回答
49 浏览
提问于 2025-04-14 17:03

问题: 我想让客户端在服务器无法连接时,使用定时器发送ping或文本消息来重试连接。客户端希望从服务器收到pong或文本消息,以便开始处理一些数据。

服务器在前20秒内没有监听任何连接,这样做是为了模拟连接问题。20秒后,我让服务器开始监听,这样它就可以接受连接请求了。

如果客户端在第一次尝试连接时,或者在这20秒内没有监听的时间段内无法连接到服务器,即使服务器之后开始监听,客户端也不会再尝试连接。不过,如果我在服务器切换到监听状态后再运行客户端,一切就会正常工作。我该如何解决这个问题,让客户端能够发送ping或文本消息?现在看起来客户端进入了一个循环,这让它无法发送ping或文本消息。

客户端部分:

from time import sleep
import sys
from PySide6 import QtCore, QtWebSockets
from PySide6.QtCore import QUrl, QTimer
from PySide6.QtWidgets import QApplication


class Client(QtCore.QObject):
    def __init__(self, parent):
        super().__init__(parent)

        self.client = QtWebSockets.QWebSocket("", QtWebSockets.QWebSocketProtocol.Version13, None)
        self.client.open(QUrl("ws://127.0.0.1:6000"))
        self.client.textMessageReceived.connect(self.process_message)
        self.client.pong.connect(self.get_pong)
        # self.client.error.connect(self.error)

        self.date_list = ['2000-01-01']

        self.check_status_timer = QTimer()
        self.check_status_timer.timeout.connect(self.send_ping)
        self.check_status_timer.start(2000)

    # some data processing after connection established
    def process(self, day):
        print(f"Day {day}")
        for i in range(10):
            print(f"Sleeping {9 - i}")
            sleep(.5)
        print("emitted")
        return True

    def create_and_run(self):
        current_date = self.date_list[0]
        result = self.process(current_date)
        if result:
            self.send_message()
        else:
            print("PROCESS FAILED")

    def process_message(self, message):
        if message == "ping" or message == "True":
            self.check_status_timer.stop()
            self.create_and_run()

    def get_pong(self):
        print("PONG")

    def send_ping(self):
        print("SENDING PING")
        self.client.ping()
        self.client.sendTextMessage("ping")

    def send_message(self):
        self.client.sendTextMessage("Client0")

    def error(self, error_code):
        print("error code: {}".format(error_code))


if __name__ == "__main__":
    app = QApplication(sys.argv)
    client = Client(app)
    app.exec()

服务器部分:

from PySide6 import QtCore, QtWebSockets, QtNetwork
from PySide6.QtWidgets import QApplication


class MyServer(QtCore.QObject):
    def __init__(self, parent):
        super().__init__(parent)
        self.clients = []
        self.server = QtWebSockets.QWebSocketServer(parent.serverName(), parent.secureMode(), parent)
        self.server.acceptError.connect(self.on_accept_error)
        self.server.newConnection.connect(self.on_new_connection)
        
        # create timer so server will switch to listening state later
        self.count = 0
        self.timer_listen = QtCore.QTimer()
        self.timer_listen.timeout.connect(self.make_listen)
        self.timer_listen.start(2000)
    
    def make_listen(self):
        if self.count >= 10:
            self.timer_listen.stop()
            self.server.listen(QtNetwork.QHostAddress.LocalHost, 6000)
            print(self.count, self.server.isListening())
        else:
            print(self.count, self.server.isListening())
            self.count += 1

    def on_accept_error(accept_error):
        print("Accept Error: {}".format(accept_error))

    def on_new_connection(self):
        client_connection = self.server.nextPendingConnection()
        client_connection.textMessageReceived.connect(self.process_message)
        client_connection.disconnected.connect(self.disconnect)
        self.clients.append(client_connection)

    def process_message(self, message):
        print(message)
        if message == "ping":
            self.sender().sendTextMessage("ping")

    def disconnect(self):
        if self.sender() in self.clients:
            self.clients.remove(self.sender())
            self.sender().deleteLater()


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    serverObject = QtWebSockets.QWebSocketServer('My Socket', QtWebSockets.QWebSocketServer.NonSecureMode)
    server = MyServer(serverObject)
    serverObject.closed.connect(app.quit)
    app.exec()

我尝试使用工作类来防止客户端的主循环冻结,也尝试了子类化QWebsocket,但都没有成功。

1 个回答

0

根据ekhumoro评论区提供的解决方案

from time import sleep
import sys
from PySide6 import QtCore, QtWebSockets
from PySide6.QtCore import QUrl, QTimer
from PySide6.QtWidgets import QApplication
from PySide6.QtNetwork import QAbstractSocket

class Client(QtCore.QObject):
    def __init__(self, parent):
        super().__init__(parent)

        self.client = QtWebSockets.QWebSocket("", QtWebSockets.QWebSocketProtocol.Version13, None)

        self.client.textMessageReceived.connect(self.process_message)
        self.client.pong.connect(self.get_pong)
        # self.client.error.connect(self.error)

        self.date_list = ['2000-01-01']

        self.check_status_timer = QTimer()
        self.check_status_timer.timeout.connect(self.send_ping)
        self.check_status_timer.start(2000)

    def process(self, day):
        print(f"Day {day}")
        for i in range(10):
            print(f"Sleeping {9 - i}")
            sleep(.5)
        print("emitted")
        return True

    def create_and_run(self):
        current_date = self.date_list[0]
        result = self.process(current_date)
        if result:
            self.send_message()
        else:
            print("PROCESS FAILED")

    def process_message(self, message):
        if message == "ping" or message == "True":
            self.check_status_timer.stop()
            self.create_and_run()

    def get_pong(self):
        print("PONG")

    def send_ping(self):
        print("SENDING PING")
        if self.client.state() == QAbstractSocket.SocketState.ConnectedState:
            self.client.ping()
            self.client.sendTextMessage("ping")
        else:
            self.client.open(QUrl("ws://127.0.0.1:6000"))


    def send_message(self):
        self.client.sendTextMessage("Client0")

    def error(self, error_code):
        print("error code: {}".format(error_code))


if __name__ == "__main__":
    app = QApplication(sys.argv)
    client = Client(app)
    app.exec()

撰写回答