如何在单独的线程中运行websocket服务器?

问题描述 投票:0回答:1

我正在使用 Python 创建一个桌面应用程序,并使用 Vue 3 编写 GUI,并且我需要在单独的线程中运行 WebSocket 服务器。问题是 WebSocket 服务器必须持续侦听传入连接以实现与客户端的实时通信,并且我不确定如何在新线程中运行它,这是必要的,因为否则 GUI 将无法启动。有谁知道应该如何实施?因为我不知道该怎么做。

主要代码:

import asyncio
import webview
import threading
from services.HttpServer import HttpServerService
from services.WebSocket import WebSocketService
 
def on_loaded(window_ready):
    webview.windows[0].events.loaded -= on_loaded
    print('Val', window_ready);
    if (window_ready):
        webview.windows[0].set_window_size(width=1200, height=800)
 
class App:
    def __init__(self):
        self.http_server_thread = None
        self.websocket_thread = None
        self.client_ui_thread = None
        self.websocket = None
        self.client_ui = None
        self.webview = webview
 
    async def start(self):
        self.http_server_thread = threading.Thread(target=HttpServerService("127.0.0.1", 8001).start)
        self.http_server_thread.daemon = True  # Set the thread as daemon
        self.http_server_thread.start()
 
        self.websocket = WebSocketService("127.0.0.1", 8008)
        self.websocket_thread = threading.Thread(target=await self.websocket.start)
        self.websocket_thread.daemon = True  # Set the thread as daemon
        self.websocket_thread.start()
 
        self.client_ui = webview.create_window("CrowdQuant", url="http://127.0.0.1:8001", width=1024, height=770,
                                               resizable=False, frameless=True)
        self.client_ui.events.loaded += lambda: self.websocket.on_message(variable_name="window_ready",
                                                                          handle_message_fn=lambda
                                                                              window_ready: on_loaded(window_ready))
 
        self.client_ui_thread = threading.Thread(target=webview.start)  # gui="cef"
        self.client_ui_thread.daemon = True  # Set the thread as daemon
        self.client_ui_thread.start()

if __name__ == "__main__":
    asyncio.run(App().start())

WebSocket服务代码:

import json
import asyncio
import websockets
 
class WebSocketService:
    def __init__(self, address="127.0.0.0", port=8008):
        self.socket = None
        self.url = (address, port)
        self.variable_name = None
        self.handle_message_fn = None
        self.server = None
        self.clients = set()
 
    async def start(self):
        await self.start_server()
        await self.start_client()
 
    async def start_server(self):
        while True:
            try:
                self.server = await websockets.serve(self.handle_client_connection, self.url[0], self.url[1])
                print(f"WebSocket server started at ws://{self.url[0]}:{self.url[1]}")
                await self.server.wait_closed()
            except OSError:
                print(f"Address {self.url[0]}:{self.url[1]} already in use. Retrying...")
                await asyncio.sleep(5)
 
    async def handle_client_connection(self, websocket):
        self.clients.add(websocket)
        try:
            async for message in websocket:
                await self.handle_message(message)
        finally:
            self.clients.remove(websocket)
 
    async def stop(self):
        await self.stop_client()
        await self.stop_server()
 
    async def stop_server(self):
        if self.server:
            self.server.close()
            await self.server.wait_closed()
 
    @staticmethod
    def on_error(error):
        print('WebSocket error:', error)
python multithreading user-interface websocket vuejs3
1个回答
0
投票

您的实施似乎总体上是在正确的轨道上,但有一些问题需要解决。让我们一步一步地看一下它们。

线程中的异步:您正在尝试将异步与线程一起使用,这并不简单。尽管可以在线程中运行 asyncio,但由于其复杂性和潜在的问题,通常不建议这样做。

启动 WebSocket 服务:由于 asyncio 不容易与设置中的线程集成,因此您应该考虑直接在 asyncio 事件循环中运行 WebSocket 服务器,而不是尝试在单独的线程中运行它。

以下是如何修改代码以将 WebSocket 服务器集成到 asyncio 事件循环中:

import asyncio
import webview
import threading
from services.HttpServer import HttpServerService
from services.WebSocket import WebSocketService

def on_loaded(window_ready):
    webview.windows[0].events.loaded -= on_loaded
    print('Val', window_ready);
    if (window_ready):
        webview.windows[0].set_window_size(width=1200, height=800)

class App:
    def __init__(self):
        self.http_server_thread = None
        self.client_ui_thread = None
        self.websocket = None
        self.client_ui = None
        self.webview = webview

    async def start(self):
        self.http_server_thread = threading.Thread(target=HttpServerService("127.0.0.1", 8001).start)
        self.http_server_thread.daemon = True
        self.http_server_thread.start()

        self.websocket = WebSocketService("127.0.0.1", 8008)
        await self.websocket.start_server()  # Start WebSocket server directly

        self.client_ui = webview.create_window("CrowdQuant", url="http://127.0.0.1:8001", width=1024, height=770,
                                               resizable=False, frameless=True)
        self.client_ui.events.loaded += lambda: self.websocket.on_message(variable_name="window_ready",
                                                                          handle_message_fn=lambda
                                                                              window_ready: on_loaded(window_ready))

        self.client_ui_thread = threading.Thread(target=webview.start)
        self.client_ui_thread.daemon = True
        self.client_ui_thread.start()

if __name__ == "__main__":
    asyncio.run(App().start())

对于 WebSocketService,您可以保持代码不变,因为它已经正确使用了 asyncio。

通过进行这些更改,您应该让 WebSocket 服务器与 GUI 应用程序一起运行,而不需要线程。

© www.soinside.com 2019 - 2024. All rights reserved.