QWebSocket客户端无法重连延迟启动监听的QWebSocketServer问题
问题描述
我需要让QWebSocket客户端在服务器不可达时,通过QTimer发送ping/text消息实现重连,且客户端必须收到服务器的pong/text消息后才启动数据处理流程。
服务器启动后前20秒不监听入站连接(模拟连接异常),20秒后才开始监听并接受连接。
当前问题:若客户端首次尝试连接或在服务器未监听的20秒内连接失败,即使后续服务器启动监听,客户端也无法建立连接;但如果在服务器已启动监听后再运行客户端,则一切正常。目前客户端似乎陷入循环,无法发送ping/text消息,此前尝试用Worker类避免主线程冻结、子类化QWebSocket均未解决问题。
客户端原始代码
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) # 连接建立后的 data processing 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) # 创建定时器延迟启动监听 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()
问题分析与修复方案
核心问题
- 未处理连接状态变化:客户端仅在初始化时调用一次
open(),首次连接失败后不会自动重试,后续ping/text消息均在未连接状态发送,无实际作用。 - 阻塞事件循环:
process()方法中使用sleep(),直接阻塞Qt事件循环,导致定时器、信号处理全部停滞,客户端假死。 - 服务器代码bug:
on_accept_error方法缺少self参数,运行时会抛出异常;disconnect方法名与Qt内置方法冲突,可能引发问题。
修复后的客户端代码
import sys from PySide6 import QtCore, QtWebSockets from PySide6.QtCore import QUrl, QTimer, Signal from PySide6.QtWidgets import QApplication class Client(QtCore.QObject): process_finished = Signal(bool) def __init__(self, parent): super().__init__(parent) self.client = QtWebSockets.QWebSocket("", QtWebSockets.QWebSocketProtocol.Version13, None) # 连接核心状态信号 self.client.connected.connect(self.on_connected) self.client.disconnected.connect(self.on_disconnected) self.client.error.connect(self.on_error) self.client.textMessageReceived.connect(self.process_message) self.client.pong.connect(self.get_pong) self.date_list = ['2000-01-01'] self.process_step = 0 self.process_timer = QTimer() self.process_timer.timeout.connect(self.process_step_run) # 重连定时器:连接失败/断开时自动重试 self.reconnect_timer = QTimer() self.reconnect_timer.setInterval(2000) self.reconnect_timer.timeout.connect(self.try_reconnect) # Ping定时器:仅在连接成功后启动 self.ping_timer = QTimer() self.ping_timer.setInterval(2000) self.ping_timer.timeout.connect(self.send_ping) # 首次尝试连接 self.try_reconnect() def try_reconnect(self): if not self.client.isValid(): print("尝试连接服务器...") self.client.open(QUrl("ws://127.0.0.1:6000")) def on_connected(self): print("连接成功") self.reconnect_timer.stop() self.ping_timer.start() def on_disconnected(self): print("连接断开,启动重连") self.ping_timer.stop() self.reconnect_timer.start() def on_error(self, error_code): print(f"错误代码: {error_code}") self.reconnect_timer.start() # 用定时器分步执行处理逻辑,避免阻塞事件循环 def start_process(self, day): print(f"Day {day}") self.process_step = 0 self.process_timer.start(500) def process_step_run(self): if self.process_step < 10: print(f"Sleeping {9 - self.process_step}") self.process_step += 1 else: self.process_timer.stop() print("emitted") self.process_finished.emit(True) def create_and_run(self): current_date = self.date_list[0] self.start_process(current_date) self.process_finished.connect(self.on_process_finished) def on_process_finished(self, result): if result: self.send_message() else: print("PROCESS FAILED") def process_message(self, message): if message == "ping" or message == "True": self.ping_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") 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) # 创建定时器延迟启动监听 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(self, accept_error): # 补全self参数 print(f"Accept Error: {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_client) # 重命名方法避免冲突 self.clients.append(client_connection) def process_message(self, message): print(message) if message == "ping": self.sender().sendTextMessage("ping") def disconnect_client(self): client = self.sender() if client in self.clients: self.clients.remove(client) client.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()
关键修改说明
- 连接状态自动化管理:新增
reconnect_timer,在连接失败或断开时自动重试;连接成功后切换为ping_timer发送心跳,确保仅在有效连接时发送ping。 - 非阻塞数据处理:将原
process()中的sleep()替换为QTimer分步执行,彻底避免阻塞Qt事件循环,保证客户端响应正常。 - 修复服务器bug:补全
on_accept_error的self参数,重命名disconnect方法避免与Qt内置方法冲突。 - 信号驱动流程:用
process_finished信号触发后续消息发送,完全遵循Qt的信号槽机制,避免同步阻塞。
内容的提问来源于stack exchange,提问作者Masquerade
相关产品推荐
相关产品推荐

